diff --git a/.github/workflows/docker-build-test.yml b/.github/workflows/docker-build-test.yml index f9058aefd..edae497ee 100644 --- a/.github/workflows/docker-build-test.yml +++ b/.github/workflows/docker-build-test.yml @@ -5,6 +5,7 @@ on: paths-ignore: - 'aider/website/**' - README.md + - HISTORY.md branches: - main pull_request: @@ -26,22 +27,24 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} - env: - dockerhub_username: ${{ secrets.DOCKERHUB_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_PASSWORD }} - if: ${{ env.dockerhub_username }} && ${{ env.dockerhub_password }} - - name: Build Docker image + - name: Build Docker standard image uses: docker/build-push-action@v5 with: context: . file: ./docker/Dockerfile platforms: linux/amd64,linux/arm64 push: false + target: aider + + - name: Build Docker full image + uses: docker/build-push-action@v5 + with: + context: . + file: ./docker/Dockerfile + platforms: linux/amd64,linux/arm64 + push: false + target: aider-full diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index c3e28dac3..1eb78382e 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -70,15 +70,15 @@ jobs: id: deployment uses: actions/deploy-pages@v2 - - name: Set up Python ${{ matrix.python-version }} + - name: Set up Python 3.12 uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python-version }} + python-version: '3.12' - name: Install linkchecker run: | python -m pip install --upgrade pip - pip install linkchecker + python -m pip install linkchecker - name: Run linkchecker run: | diff --git a/.github/workflows/ubuntu-tests.yml b/.github/workflows/ubuntu-tests.yml index ac094d3b7..3654df7bb 100644 --- a/.github/workflows/ubuntu-tests.yml +++ b/.github/workflows/ubuntu-tests.yml @@ -5,6 +5,7 @@ on: paths-ignore: - 'aider/website/**' - README.md + - HISTORY.md branches: - main pull_request: diff --git a/.github/workflows/windows-tests.yml b/.github/workflows/windows-tests.yml index 431326fc4..c79b0dd5f 100644 --- a/.github/workflows/windows-tests.yml +++ b/.github/workflows/windows-tests.yml @@ -5,6 +5,7 @@ on: paths-ignore: - 'aider/website/**' - README.md + - HISTORY.md branches: - main pull_request: diff --git a/.gitignore b/.gitignore index ae668b707..df9efed89 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,7 @@ dist/ Gemfile.lock _site .jekyll-cache/ -.jekyll-metadata \ No newline at end of file +.jekyll-metadata +aider/__version__.py +.venv/ +.gitattributes diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index daec59aae..2a62f51e1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,3 +14,9 @@ repos: hooks: - id: flake8 args: ["--show-source"] + - repo: https://github.com/codespell-project/codespell + rev: v2.2.6 + hooks: + - id: codespell + additional_dependencies: + - tomli diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 22bcece77..648256e10 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,10 +17,10 @@ Contributions of [LLM benchmark results](https://aider.chat/docs/leaderboards/) are welcome! See the -[benchmark README](https://github.com/paul-gauthier/aider/blob/main/benchmark/README.md) +[benchmark README](https://github.com/Aider-AI/aider/blob/main/benchmark/README.md) for information on running aider's code editing benchmarks. Submit results by opening a PR with edits to the -[benchmark results data files](https://github.com/paul-gauthier/aider/blob/main/_data/). +[benchmark results data files](https://github.com/Aider-AI/aider/blob/main/aider/website/_data/). ## Pull Requests @@ -33,19 +33,16 @@ ensure that your contributions can be integrated smoothly. ## Licensing -By contributing to this project, you agree that your contributions -will be licensed under the Apache License 2.0. Additionally, you -understand and agree that contributions may be subject to a different -license, should the project maintainers decide to change the licensing -terms. - +Before contributing a PR, please review our +[Individual Contributor License Agreement](https://aider.chat/docs/legal/contributor-agreement.html). +All contributors will be asked to complete the agreement as part of the PR process. ## Setting up a Development Environment ### Clone the Repository ``` -git clone https://github.com/paul-gauthier/aider.git +git clone https://github.com/Aider-AI/aider.git cd aider ``` @@ -154,6 +151,10 @@ The project's documentation is built using Jekyll and hosted on GitHub Pages. To ``` bundle exec jekyll build ``` +5. Preview the website while editing (optional): + ``` + bundle exec jekyll serve + ``` The built documentation will be available in the `aider/website/_site` directory. @@ -186,8 +187,8 @@ pytest You can also run specific test files or test cases by providing the file path or test name: ``` -pytest aider/tests/test_coder.py -pytest aider/tests/test_coder.py::TestCoder::test_specific_case +pytest tests/basic/test_coder.py +pytest tests/basic/test_coder.py::TestCoder::test_specific_case ``` #### Continuous Integration diff --git a/HISTORY.md b/HISTORY.md index 1d0b31e89..e2785d6f0 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,324 @@ - # Release history +### main branch + +- PDF support for Sonnet and Gemini models. +- Set cwd to repo root when running shell commands. +- Improved error handling for failed .gitignore file operations. +- Improved error handling for input history file permissions. +- Improved error handling for analytics file access. +- Aider wrote 85% of the code in this release. + +### Aider v0.65.1 + +- Bugfix to `--alias`. + +### Aider v0.65.0 + +- Added `--alias` config to define [custom model aliases](https://aider.chat/docs/config/model-aliases.html). +- Added `--[no-]detect-urls` flag to disable detecting and offering to scrape URLs found in the chat. +- Ollama models now default to an 8k context window. +- Added [RepoMap support for Dart language](https://aider.chat/docs/languages.html) by @malkoG. +- Ask 2.5% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html). +- Skip suggesting files that share names with files already in chat. +- `/editor` returns and prefill the file content into the prompt, so you can use `/editor` to compose messages that start with `/commands`, etc. +- Enhanced error handling for analytics. +- Improved handling of UnknownEditFormat exceptions with helpful documentation links. +- Bumped dependencies to pick up grep-ast 0.4.0 for Dart language support. +- Aider wrote 81% of the code in this release. + +### Aider v0.64.1 + +- Disable streaming for o1 on OpenRouter. + +### Aider v0.64.0 + +- Added [`/editor` command](https://aider.chat/docs/usage/commands.html) to open system editor for writing prompts, by @thehunmonkgroup. +- Full support for `gpt-4o-2024-11-20`. +- Stream o1 models by default. +- `/run` and suggested shell commands are less mysterious and now confirm that they "Added XX lines of output to the chat." +- Ask 1% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html). +- Added support for [optional multiline input tags](https://aider.chat/docs/usage/commands.html#entering-multi-line-chat-messages) with matching closing tags. +- Improved [model settings configuration](https://aider.chat/docs/config/adv-model-settings.html#global-extra-params) with support for global `extra_params` for `litellm.completion()`. +- Architect mode now asks to add files suggested by the LLM. +- Fixed bug in fuzzy model name matching. +- Added Timeout exception to handle API provider timeouts. +- Added `--show-release-notes` to control release notes display on first run of new version. +- Save empty dict to cache file on model metadata download failure, to delay retry. +- Improved error handling and code formatting. +- Aider wrote 74% of the code in this release. + +### Aider v0.63.2 + +- Fixed bug in fuzzy model name matching when litellm provider info is missing. +- Modified model metadata file loading to allow override of resource file. +- Allow recursive loading of dirs using `--read`. +- Updated dependency versions to pick up litellm fix for ollama models. +- Added exponential backoff retry when writing files to handle editor file locks. +- Updated Qwen 2.5 Coder 32B model configuration. + +### Aider v0.63.1 + +- Fixed bug in git ignored file handling. +- Improved error handling for git operations. + +### Aider v0.63.0 + +- Support for Qwen 2.5 Coder 32B. +- `/web` command just adds the page to the chat, without triggering an LLM response. +- Improved prompting for the user's preferred chat language. +- Improved handling of LiteLLM exceptions. +- Bugfix for double-counting tokens when reporting cache stats. +- Bugfix for the LLM creating new files. +- Other small bug fixes. +- Aider wrote 55% of the code in this release. + +### Aider v0.62.0 + +- Full support for Claude 3.5 Haiku + - Scored 75% on [aider's code editing leaderboard](https://aider.chat/docs/leaderboards/). + - Almost as good as Sonnet at much lower cost. + - Launch with `--haiku` to use it. +- Easily apply file edits from ChatGPT, Claude or other web apps + - Chat with ChatGPT or Claude via their web app. + - Give it your source files and ask for the changes you want. + - Use the web app's "copy response" button to copy the entire reply from the LLM. + - Run `aider --apply-clipboard-edits file-to-edit.js`. + - Aider will edit your file with the LLM's changes. +- Bugfix for creating new files. +- Aider wrote 84% of the code in this release. + +### Aider v0.61.0 + +- Load and save aider slash-commands to files: + - `/save ` command will make a file of `/add` and `/read-only` commands that recreate the current file context in the chat. + - `/load ` will replay the commands in the file. + - You can use `/load` to run any arbitrary set of slash-commands, not just `/add` and `/read-only`. + - Use `--load ` to run a list of commands on launch, before the interactive chat begins. +- Anonymous, opt-in [analytics](https://aider.chat/docs/more/analytics.html) with no personal data sharing. +- Aider follows litellm's `supports_vision` attribute to enable image support for models. +- Bugfix for when diff mode flexibly handles the model using the wrong filename. +- Displays filenames in sorted order for `/add` and `/read-only`. +- New `--no-fancy-input` switch disables prompt toolkit input, now still available with `--no-pretty`. +- Override browser config with `--no-browser` or `--no-gui`. +- Offer to open documentation URLs when errors occur. +- Properly support all o1 models, regardless of provider. +- Improved layout of filenames above input prompt. +- Better handle corrupted repomap tags cache. +- Improved handling of API errors, especially when accessing the weak model. +- Aider wrote 68% of the code in this release. + +### Aider v0.60.1 + +- Enable image support for Sonnet 10/22. +- Display filenames in sorted order. + +### Aider v0.60.0 + +- Full support for Sonnet 10/22, the new SOTA model on aider's code editing benchmark. + - Aider uses Sonnet 10/22 by default. +- Improved formatting of added and read-only files above chat prompt, by @jbellis. +- Improved support for o1 models by more flexibly parsing their nonconforming code edit replies. +- Corrected diff edit format prompt that only the first match is replaced. +- Stronger whole edit format prompt asking for clean file names. +- Now offers to add `.env` to the `.gitignore` file. +- Ships with a small model metadata json file to handle models not yet updated in litellm. +- Model settings for o1 models on azure. +- Bugfix to properly include URLs in `/help` RAG results. +- Aider wrote 49% of the code in this release. + +### Aider v0.59.1 + +- Check for obsolete `yes: true` in yaml config, show helpful error. +- Model settings for openrouter/anthropic/claude-3.5-sonnet:beta + +### Aider v0.59.0 + +- Improvements to `/read-only`: + - Now supports shell-style auto-complete of the full file system. + - Still auto-completes the full paths of the repo files like `/add`. + - Now supports globs like `src/**/*.py` +- Renamed `--yes` to `--yes-always`. + - Now uses `AIDER_YES_ALWAYS` env var and `yes-always:` yaml key. + - Existing YAML and .env files will need to be updated. + - Can still abbreviate to `--yes` on the command line. +- Config file now uses standard YAML list syntax with ` - list entries`, one per line. +- `/settings` now includes the same announcement lines that would print at launch. +- Sanity checks the `--editor-model` on launch now, same as main and weak models. +- Added `--skip-sanity-check-repo` switch to speedup launch in large repos. +- Bugfix so architect mode handles Control-C properly. +- Repo-map is deterministic now, with improved caching logic. +- Improved commit message prompt. +- Aider wrote 77% of the code in this release. + +### Aider v0.58.1 + +- Fixed bug where cache warming pings caused subsequent user messages to trigger a tight loop of LLM requests. + +### Aider v0.58.0 + +- [Use a pair of Architect/Editor models for improved coding](https://aider.chat/2024/09/26/architect.html) + - Use a strong reasoning model like o1-preview as your Architect. + - Use a cheaper, faster model like gpt-4o as your Editor. +- New `--o1-preview` and `--o1-mini` shortcuts. +- Support for new Gemini 002 models. +- Better support for Qwen 2.5 models. +- Many confirmation questions can be skipped for the rest of the session with "(D)on't ask again" response. +- Autocomplete for `/read-only` supports the entire filesystem. +- New settings for completion menu colors. +- New `/copy` command to copy the last LLM response to the clipboard. +- Renamed `/clipboard` to `/paste`. +- Will now follow HTTP redirects when scraping urls. +- New `--voice-format` switch to send voice audio as wav/mp3/webm, by @mbailey. +- ModelSettings takes `extra_params` dict to specify any extras to pass to `litellm.completion()`. +- Support for cursor shapes when in vim mode. +- Numerous bug fixes. +- Aider wrote 53% of the code in this release. + +### Aider v0.57.1 + +- Fixed dependency conflict between aider-chat[help] and [playwright]. + +### Aider v0.57.0 + +- Support for OpenAI o1 models: + - o1-preview now works well with diff edit format. + - o1-preview with diff now matches SOTA leaderboard result with whole edit format. + - `aider --model o1-mini` + - `aider --model o1-preview` +- On Windows, `/run` correctly uses PowerShell or cmd.exe. +- Support for new 08-2024 Cohere models, by @jalammar. +- Can now recursively add directories with `/read-only`. +- User input prompts now fall back to simple `input()` if `--no-pretty` or a Windows console is not available. +- Improved sanity check of git repo on startup. +- Improvements to prompt cache chunking strategy. +- Removed "No changes made to git tracked files". +- Numerous bug fixes for corner case crashes. +- Updated all dependency versions. +- Aider wrote 70% of the code in this release. + +### Aider v0.56.0 + +- Enables prompt caching for Sonnet via OpenRouter by @fry69 +- Enables 8k output tokens for Sonnet via VertexAI and DeepSeek V2.5. +- New `/report` command to open your browser with a pre-populated GitHub Issue. +- New `--chat-language` switch to set the spoken language. +- Now `--[no-]suggest-shell-commands` controls both prompting for and offering to execute shell commands. +- Check key imports on launch, provide helpful error message if dependencies aren't available. +- Renamed `--models` to `--list-models` by @fry69. +- Numerous bug fixes for corner case crashes. +- Aider wrote 56% of the code in this release. + +### Aider v0.55.0 + +- Only print the pip command when self updating on Windows, without running it. +- Converted many error messages to warning messages. +- Added `--tool-warning-color` setting. +- Blanket catch and handle git errors in any `/command`. +- Catch and handle glob errors in `/add`, errors writing files. +- Disabled built in linter for typescript. +- Catch and handle terminals which don't support pretty output. +- Catch and handle playwright and pandoc errors. +- Catch `/voice` transcription exceptions, show the WAV file so the user can recover it. +- Aider wrote 53% of the code in this release. + +### Aider v0.54.12 + +- Switched to `vX.Y.Z.dev` version naming. + +### Aider v0.54.11 + +- Improved printed pip command output on Windows. + +### Aider v0.54.10 + +- Bugfix to test command in platform info. + +### Aider v0.54.9 + +- Include important devops files in the repomap. +- Print quoted pip install commands to the user. +- Adopt setuptools_scm to provide dev versions with git hashes. +- Share active test and lint commands with the LLM. +- Catch and handle most errors creating new files, reading existing files. +- Catch and handle most git errors. +- Added --verbose debug output for shell commands. + +### Aider v0.54.8 + +- Startup QOL improvements: + - Sanity check the git repo and exit gracefully on problems. + - Pause for confirmation after model sanity check to allow user to review warnings. +- Bug fix for shell commands on Windows. +- Do not fuzzy match filenames when LLM is creating a new file, by @ozapinq +- Numerous corner case bug fixes submitted via new crash report -> GitHub Issue feature. +- Crash reports now include python version, OS, etc. + +### Aider v0.54.7 + +- Offer to submit a GitHub issue pre-filled with uncaught exception info. +- Bugfix for infinite output. + +### Aider v0.54.6 + +- New `/settings` command to show active settings. +- Only show cache warming status update if `--verbose`. + +### Aider v0.54.5 + +- Bugfix for shell commands on Windows. +- Refuse to make git repo in $HOME, warn user. +- Don't ask again in current session about a file the user has said not to add to the chat. +- Added `--update` as an alias for `--upgrade`. + +### Aider v0.54.4 + +- Bugfix to completions for `/model` command. +- Bugfix: revert home dir special case. + +### Aider v0.54.3 + +- Dependency `watchdog<5` for docker image. + +### Aider v0.54.2 + +- When users launch aider in their home dir, help them find/create a repo in a subdir. +- Added missing `pexpect` dependency. + +### Aider v0.54.0 + +- Added model settings for `gemini/gemini-1.5-pro-exp-0827` and `gemini/gemini-1.5-flash-exp-0827`. +- Shell and `/run` commands can now be interactive in environments where a pty is available. +- Optionally share output of suggested shell commands back to the LLM. +- New `--[no-]suggest-shell-commands` switch to configure shell commands. +- Performance improvements for autocomplete in large/mono repos. +- New `--upgrade` switch to install latest version of aider from pypi. +- Bugfix to `--show-prompt`. +- Disabled automatic reply to the LLM on `/undo` for all models. +- Removed pager from `/web` output. +- Aider wrote 64% of the code in this release. + +### Aider v0.53.0 + +- [Keep your prompt cache from expiring](https://aider.chat/docs/usage/caching.html#preventing-cache-expiration) with `--cache-keepalive-pings`. + - Pings the API every 5min to keep the cache warm. +- You can now bulk accept/reject a series of add url and run shell confirmations. +- Improved matching of filenames from S/R blocks with files in chat. +- Stronger prompting for Sonnet to make edits in code chat mode. +- Stronger prompting for the LLM to specify full file paths. +- Improved shell command prompting. +- Weak model now uses `extra_headers`, to support Anthropic beta features. +- New `--install-main-branch` to update to the latest dev version of aider. +- Improved error messages on attempt to add not-git subdir to chat. +- Show model metadata info on `--verbose`. +- Improved warnings when LLMs env variables aren't set. +- Bugfix to windows filenames which contain `\_`. +- Aider wrote 59% of the code in this release. + +### Aider v0.52.1 + +- Bugfix for NameError when applying edits. + ### Aider v0.52.0 - Aider now offers to run shell commands: @@ -521,7 +839,7 @@ ### Aider v0.14.0 - [Support for Claude2 and other LLMs via OpenRouter](https://aider.chat/docs/faq.html#accessing-other-llms-with-openrouter) by @joshuavial -- Documentation for [running the aider benchmarking suite](https://github.com/paul-gauthier/aider/tree/main/benchmark) +- Documentation for [running the aider benchmarking suite](https://github.com/Aider-AI/aider/tree/main/benchmark) - Aider now requires Python >= 3.9 @@ -566,7 +884,7 @@ - Added `/git` command to run git from inside aider chats. - Use Meta-ENTER (Esc+ENTER in some environments) to enter multiline chat messages. -- Create a `.gitignore` with `.aider*` to prevent users from accidentaly adding aider files to git. +- Create a `.gitignore` with `.aider*` to prevent users from accidentally adding aider files to git. - Check pypi for newer versions and notify user. - Updated keyboard interrupt logic so that 2 ^C in 2 seconds always forces aider to exit. - Provide GPT with detailed error if it makes a bad edit block, ask for a retry. diff --git a/README.md b/README.md index 25a9399f4..b19b01074 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,23 @@ 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). +

aider screencast

+ + +

@@ -35,7 +46,7 @@ cog.out(open("aider/website/_includes/get-started.md").read()) You can get started quickly like this: ``` -python -m pip install aider-chat +python -m pip install -U aider-chat # Change directory into a git repo cd /to/your/git/repo @@ -96,7 +107,7 @@ projects like django, scikitlearn, matplotlib, etc. - [Configuration](https://aider.chat/docs/config.html) - [Troubleshooting](https://aider.chat/docs/troubleshooting.html) - [LLM Leaderboards](https://aider.chat/docs/leaderboards/) -- [GitHub](https://github.com/paul-gauthier/aider) +- [GitHub](https://github.com/Aider-AI/aider) - [Discord](https://discord.gg/Tv2uQnR88V) - [Blog](https://aider.chat/blog/) @@ -107,14 +118,14 @@ projects like django, scikitlearn, matplotlib, etc. - *The best AI coding assistant so far.* -- [Matthew Berman](https://www.youtube.com/watch?v=df8afeb1FY8) - *Aider ... has easily quadrupled my coding productivity.* -- [SOLAR_FIELDS](https://news.ycombinator.com/item?id=36212100) - *It's a cool workflow... Aider's ergonomics are perfect for me.* -- [qup](https://news.ycombinator.com/item?id=38185326) -- *It's really like having your senior developer live right in your Git repo - truly amazing!* -- [rappster](https://github.com/paul-gauthier/aider/issues/124) -- *What an amazing tool. It's incredible.* -- [valyagolev](https://github.com/paul-gauthier/aider/issues/6#issue-1722897858) -- *Aider is such an astounding thing!* -- [cgrothaus](https://github.com/paul-gauthier/aider/issues/82#issuecomment-1631876700) +- *It's really like having your senior developer live right in your Git repo - truly amazing!* -- [rappster](https://github.com/Aider-AI/aider/issues/124) +- *What an amazing tool. It's incredible.* -- [valyagolev](https://github.com/Aider-AI/aider/issues/6#issue-1722897858) +- *Aider is such an astounding thing!* -- [cgrothaus](https://github.com/Aider-AI/aider/issues/82#issuecomment-1631876700) - *It was WAY faster than I would be getting off the ground and making the first few working versions.* -- [Daniel Feldman](https://twitter.com/d_feldman/status/1662295077387923456) - *THANK YOU for Aider! It really feels like a glimpse into the future of coding.* -- [derwiki](https://news.ycombinator.com/item?id=38205643) - *It's just amazing. It is freeing me to do things I felt were out my comfort zone before.* -- [Dougie](https://discord.com/channels/1131200896827654144/1174002618058678323/1174084556257775656) -- *This project is stellar.* -- [funkytaco](https://github.com/paul-gauthier/aider/issues/112#issuecomment-1637429008) -- *Amazing project, definitely the best AI coding assistant I've used.* -- [joshuavial](https://github.com/paul-gauthier/aider/issues/84) +- *This project is stellar.* -- [funkytaco](https://github.com/Aider-AI/aider/issues/112#issuecomment-1637429008) +- *Amazing project, definitely the best AI coding assistant I've used.* -- [joshuavial](https://github.com/Aider-AI/aider/issues/84) - *I absolutely love using Aider ... It makes software development feel so much lighter as an experience.* -- [principalideal0](https://discord.com/channels/1131200896827654144/1133421607499595858/1229689636012691468) - *I have been recovering from multiple shoulder surgeries ... and have used aider extensively. It has allowed me to continue productivity.* -- [codeninja](https://www.reddit.com/r/OpenAI/s/nmNwkHy1zG) - *I am an aider addict. I'm getting so much more work done, but in less time.* -- [dandandan](https://discord.com/channels/1131200896827654144/1131200896827654149/1135913253483069470) diff --git a/aider/__init__.py b/aider/__init__.py index 21ecfbb6d..db056f0ff 100644 --- a/aider/__init__.py +++ b/aider/__init__.py @@ -1 +1,6 @@ -__version__ = "0.52.1-dev" +try: + from aider.__version__ import __version__ +except Exception: + __version__ = "0.65.2.dev" + +__all__ = [__version__] diff --git a/aider/analytics.py b/aider/analytics.py new file mode 100644 index 000000000..82c888247 --- /dev/null +++ b/aider/analytics.py @@ -0,0 +1,220 @@ +import json +import platform +import sys +import time +import uuid +from pathlib import Path + +from mixpanel import Mixpanel, MixpanelException +from posthog import Posthog + +from aider import __version__ +from aider.dump import dump # noqa: F401 +from aider.models import model_info_manager + +mixpanel_project_token = "6da9a43058a5d1b9f3353153921fb04d" +posthog_project_api_key = "phc_99T7muzafUMMZX15H8XePbMSreEUzahHbtWjy3l5Qbv" +posthog_host = "https://us.i.posthog.com" + + +class Analytics: + # providers + mp = None + ph = None + + # saved + user_id = None + permanently_disable = None + asked_opt_in = None + + # ephemeral + logfile = None + + def __init__(self, logfile=None, permanently_disable=False): + self.logfile = logfile + self.get_or_create_uuid() + + if self.permanently_disable or permanently_disable or not self.asked_opt_in: + self.disable(permanently_disable) + + def enable(self): + if not self.user_id: + self.disable(False) + return + + if self.permanently_disable: + self.disable(True) + return + + if not self.asked_opt_in: + self.disable(False) + return + + self.mp = Mixpanel(mixpanel_project_token) + self.ph = Posthog(project_api_key=posthog_project_api_key, host=posthog_host) + + def disable(self, permanently): + self.mp = None + self.ph = None + + if permanently: + self.asked_opt_in = True + self.permanently_disable = True + self.save_data() + + def need_to_ask(self, args_analytics): + if args_analytics is False: + return False + + could_ask = not self.asked_opt_in and not self.permanently_disable + if not could_ask: + return False + + if args_analytics is True: + return True + + assert args_analytics is None, args_analytics + + if not self.user_id: + return False + + PERCENT = 2.5 + return self.is_uuid_in_percentage(self.user_id, PERCENT) + + def is_uuid_in_percentage(self, uuid_str, percent): + """Check if a UUID string falls within the first X percent of the UUID space. + + Args: + uuid_str: UUID string to test + percent: Percentage threshold (0-100) + + Returns: + bool: True if UUID falls within the first X percent + """ + if not (0 <= percent <= 100): + raise ValueError("Percentage must be between 0 and 100") + + if not uuid_str: + return False + + # Convert percentage to hex threshold (1% = "04...", 10% = "1a...", etc) + # Using first 6 hex digits + if percent == 0: + return False + threshold = format(int(0xFFFFFF * percent / 100), "06x") + return uuid_str[:6] <= threshold + + def get_data_file_path(self): + try: + data_file = Path.home() / ".aider" / "analytics.json" + data_file.parent.mkdir(parents=True, exist_ok=True) + return data_file + except OSError: + # If we can't create/access the directory, just disable analytics + self.disable(permanently=False) + return None + + def get_or_create_uuid(self): + self.load_data() + if self.user_id: + return + + self.user_id = str(uuid.uuid4()) + self.save_data() + + def load_data(self): + data_file = self.get_data_file_path() + if not data_file: + return + + if data_file.exists(): + try: + data = json.loads(data_file.read_text()) + self.permanently_disable = data.get("permanently_disable") + self.user_id = data.get("uuid") + self.asked_opt_in = data.get("asked_opt_in", False) + except (json.decoder.JSONDecodeError, OSError): + self.disable(permanently=False) + + def save_data(self): + data_file = self.get_data_file_path() + if not data_file: + return + + data = dict( + uuid=self.user_id, + permanently_disable=self.permanently_disable, + asked_opt_in=self.asked_opt_in, + ) + + try: + data_file.write_text(json.dumps(data, indent=4)) + except OSError: + # If we can't write the file, just disable analytics + self.disable(permanently=False) + + def get_system_info(self): + return { + "python_version": sys.version.split()[0], + "os_platform": platform.system(), + "os_release": platform.release(), + "machine": platform.machine(), + } + + def _redact_model_name(self, model): + if not model: + return None + + info = model_info_manager.get_model_from_cached_json_db(model.name) + if info: + return model.name + elif "/" in model.name: + return model.name.split("/")[0] + "/REDACTED" + return None + + def event(self, event_name, main_model=None, **kwargs): + if not self.mp and not self.ph and not self.logfile: + return + + properties = {} + + if main_model: + properties["main_model"] = self._redact_model_name(main_model) + properties["weak_model"] = self._redact_model_name(main_model.weak_model) + properties["editor_model"] = self._redact_model_name(main_model.editor_model) + + properties.update(kwargs) + properties.update(self.get_system_info()) # Add system info to all events + + # Handle numeric values + for key, value in properties.items(): + if isinstance(value, (int, float)): + properties[key] = value + else: + properties[key] = str(value) + + properties["aider_version"] = __version__ + + if self.mp: + try: + self.mp.track(self.user_id, event_name, dict(properties)) + except MixpanelException: + self.mp = None # Disable mixpanel on connection errors + + if self.ph: + self.ph.capture(self.user_id, event_name, dict(properties)) + + if self.logfile: + log_entry = { + "event": event_name, + "properties": properties, + "user_id": self.user_id, + "time": int(time.time()), + } + with open(self.logfile, "a") as f: + json.dump(log_entry, f) + f.write("\n") + + def __del__(self): + if self.ph: + self.ph.shutdown() diff --git a/aider/args.py b/aider/args.py index 0b32bd3c5..58a08f5a0 100644 --- a/aider/args.py +++ b/aider/args.py @@ -22,9 +22,10 @@ def default_env_file(git_root): def get_parser(default_config_files, git_root): parser = configargparse.ArgumentParser( - description="aider is GPT powered coding in your terminal", + description="aider is AI pair programming in your terminal", add_config_file_help=True, default_config_files=default_config_files, + config_file_parser_class=configargparse.YAMLConfigFileParser, auto_env_var_prefix="AIDER_", ) group = parser.add_argument_group("Main") @@ -57,7 +58,7 @@ def get_parser(default_config_files, git_root): const=opus_model, help=f"Use {opus_model} model for the main chat", ) - sonnet_model = "claude-3-5-sonnet-20240620" + sonnet_model = "claude-3-5-sonnet-20241022" group.add_argument( "--sonnet", action="store_const", @@ -65,6 +66,14 @@ def get_parser(default_config_files, git_root): const=sonnet_model, help=f"Use {sonnet_model} model for the main chat", ) + haiku_model = "claude-3-5-haiku-20241022" + group.add_argument( + "--haiku", + action="store_const", + dest="model", + const=haiku_model, + help=f"Use {haiku_model} model for the main chat", + ) gpt_4_model = "gpt-4-0613" group.add_argument( "--4", @@ -117,10 +126,27 @@ def get_parser(default_config_files, git_root): const=deepseek_model, help=f"Use {deepseek_model} model for the main chat", ) + o1_mini_model = "o1-mini" + group.add_argument( + "--o1-mini", + action="store_const", + dest="model", + const=o1_mini_model, + help=f"Use {o1_mini_model} model for the main chat", + ) + o1_preview_model = "o1-preview" + group.add_argument( + "--o1-preview", + action="store_const", + dest="model", + const=o1_preview_model, + help=f"Use {o1_preview_model} model for the main chat", + ) ########## group = parser.add_argument_group("Model Settings") group.add_argument( + "--list-models", "--models", metavar="MODEL", help="List known models which match the (partial) MODEL name", @@ -167,6 +193,12 @@ def get_parser(default_config_files, git_root): default=".aider.model.metadata.json", help="Specify a file with context window and costs for unknown models", ) + group.add_argument( + "--alias", + action="append", + metavar="ALIAS:MODEL", + help="Add a model alias (can be used multiple times)", + ) group.add_argument( "--verify-ssl", action=argparse.BooleanOptionalAction, @@ -180,6 +212,13 @@ def get_parser(default_config_files, git_root): default=None, help="Specify what edit format the LLM should use (default depends on model)", ) + group.add_argument( + "--architect", + action="store_const", + dest="edit_format", + const="architect", + help="Use architect edit format for the main chat", + ) group.add_argument( "--weak-model", metavar="WEAK_MODEL", @@ -189,12 +228,59 @@ def get_parser(default_config_files, git_root): " depends on --model)" ), ) + group.add_argument( + "--editor-model", + metavar="EDITOR_MODEL", + default=None, + help="Specify the model to use for editor tasks (default depends on --model)", + ) + group.add_argument( + "--editor-edit-format", + metavar="EDITOR_EDIT_FORMAT", + default=None, + help="Specify the edit format for the editor model (default: depends on editor model)", + ) group.add_argument( "--show-model-warnings", action=argparse.BooleanOptionalAction, default=True, help="Only work with models that have meta-data available (default: True)", ) + group.add_argument( + "--max-chat-history-tokens", + type=int, + default=None, + help=( + "Soft limit on tokens for chat history, after which summarization begins." + " If unspecified, defaults to the model's max_chat_history_tokens." + ), + ) + # This is a duplicate of the argument in the preparser and is a no-op by this time of + # argument parsing, but it's here so that the help is displayed as expected. + group.add_argument( + "--env-file", + metavar="ENV_FILE", + default=default_env_file(git_root), + help="Specify the .env file to load (default: .env in git root)", + ) + + ########## + group = parser.add_argument_group("Cache Settings") + group.add_argument( + "--cache-prompts", + action=argparse.BooleanOptionalAction, + default=False, + help="Enable caching of prompts (default: False)", + ) + group.add_argument( + "--cache-keepalive-pings", + type=int, + default=0, + help="Number of times to ping at 5min intervals to keep prompt cache warm (default: 0)", + ) + + ########## + group = parser.add_argument_group("Repomap Settings") group.add_argument( "--map-tokens", type=int, @@ -205,13 +291,10 @@ def get_parser(default_config_files, git_root): "--map-refresh", choices=["auto", "always", "files", "manual"], default="auto", - help="Control how often the repo map is refreshed (default: auto)", - ) - group.add_argument( - "--cache-prompts", - action=argparse.BooleanOptionalAction, - default=False, - help="Enable caching of prompts (default: False)", + help=( + "Control how often the repo map is refreshed. Options: auto, always, files, manual" + " (default: auto)" + ), ) group.add_argument( "--map-multiplier-no-files", @@ -219,23 +302,6 @@ def get_parser(default_config_files, git_root): default=2, help="Multiplier for map tokens when no files are specified (default: 2)", ) - group.add_argument( - "--max-chat-history-tokens", - type=int, - default=None, - help=( - "Maximum number of tokens to use for chat history. If not specified, uses the model's" - " max_chat_history_tokens." - ), - ) - # This is a duplicate of the argument in the preparser and is a no-op by this time of - # argument parsing, but it's here so that the help is displayed as expected. - group.add_argument( - "--env-file", - metavar="ENV_FILE", - default=default_env_file(git_root), - help="Specify the .env file to load (default: .env in git root)", - ) ########## group = parser.add_argument_group("History Files") @@ -309,13 +375,51 @@ def get_parser(default_config_files, git_root): group.add_argument( "--tool-error-color", default="#FF2222", - help="Set the color for tool error messages (default: red)", + help="Set the color for tool error messages (default: #FF2222)", + ) + group.add_argument( + "--tool-warning-color", + default="#FFA500", + help="Set the color for tool warning messages (default: #FFA500)", ) group.add_argument( "--assistant-output-color", default="#0088ff", help="Set the color for assistant output (default: #0088ff)", ) + group.add_argument( + "--completion-menu-color", + metavar="COLOR", + default=None, + help="Set the color for the completion menu (default: terminal's default text color)", + ) + group.add_argument( + "--completion-menu-bg-color", + metavar="COLOR", + default=None, + help=( + "Set the background color for the completion menu (default: terminal's default" + " background color)" + ), + ) + group.add_argument( + "--completion-menu-current-color", + metavar="COLOR", + default=None, + help=( + "Set the color for the current item in the completion menu (default: terminal's default" + " background color)" + ), + ) + group.add_argument( + "--completion-menu-current-bg-color", + metavar="COLOR", + default=None, + help=( + "Set the background color for the current item in the completion menu (default:" + " terminal's default text color)" + ), + ) group.add_argument( "--code-theme", default="default", @@ -413,6 +517,12 @@ def get_parser(default_config_files, git_root): default=False, help="Perform a dry run without modifying files (default: False)", ) + group.add_argument( + "--skip-sanity-check-repo", + action="store_true", + help="Skip the sanity check for the git repository (default: False)", + default=False, + ) group = parser.add_argument_group("Fixing and committing") group.add_argument( "--lint", @@ -454,6 +564,25 @@ def get_parser(default_config_files, git_root): ) ########## + group = parser.add_argument_group("Analytics") + group.add_argument( + "--analytics", + action=argparse.BooleanOptionalAction, + default=None, + help="Enable/disable analytics for current session (default: random)", + ) + group.add_argument( + "--analytics-log", + metavar="ANALYTICS_LOG_FILE", + help="Specify a file to log analytics events", + ) + group.add_argument( + "--analytics-disable", + action="store_true", + help="Permanently disable analytics", + default=False, + ) + group = parser.add_argument_group("Other Settings") group.add_argument( "--file", @@ -474,10 +603,10 @@ def get_parser(default_config_files, git_root): default=False, ) group.add_argument( - "--voice-language", - metavar="VOICE_LANGUAGE", - default="en", - help="Specify the language for voice using ISO 639-1 code (default: auto)", + "--chat-language", + metavar="CHAT_LANGUAGE", + default=None, + help="Specify the language to use in the chat (default: None, uses system settings)", ) group.add_argument( "--version", @@ -497,13 +626,38 @@ def get_parser(default_config_files, git_root): help="Check for new aider versions on launch", default=True, ) + group.add_argument( + "--show-release-notes", + action=argparse.BooleanOptionalAction, + help="Show release notes on first run of new version (default: None, ask user)", + default=None, + ) + group.add_argument( + "--install-main-branch", + action="store_true", + help="Install the latest version from the main branch", + default=False, + ) + group.add_argument( + "--upgrade", + "--update", + action="store_true", + help="Upgrade aider to the latest version from PyPI", + default=False, + ) group.add_argument( "--apply", metavar="FILE", help="Apply the changes from the given file instead of running the chat (debug)", ) group.add_argument( - "--yes", + "--apply-clipboard-edits", + action="store_true", + help="Apply clipboard contents as edits using the main model's editor format", + default=False, + ) + group.add_argument( + "--yes-always", action="store_true", help="Always say yes to every confirmation", default=None, @@ -551,6 +705,11 @@ def get_parser(default_config_files, git_root): " (disables chat mode)" ), ) + group.add_argument( + "--load", + metavar="LOAD_FILE", + help="Load and execute /commands from a file on launch", + ) group.add_argument( "--encoding", default="utf-8", @@ -569,10 +728,48 @@ def get_parser(default_config_files, git_root): group.add_argument( "--gui", "--browser", - action="store_true", - help="Run aider in your browser", + action=argparse.BooleanOptionalAction, + help="Run aider in your browser (default: False)", default=False, ) + group.add_argument( + "--suggest-shell-commands", + action=argparse.BooleanOptionalAction, + default=True, + help="Enable/disable suggesting shell commands (default: True)", + ) + group.add_argument( + "--fancy-input", + action=argparse.BooleanOptionalAction, + default=True, + help="Enable/disable fancy input with history and completion (default: True)", + ) + group.add_argument( + "--detect-urls", + action=argparse.BooleanOptionalAction, + default=True, + help="Enable/disable detection and offering to add URLs to chat (default: True)", + ) + group.add_argument( + "--editor", + help="Specify which editor to use for the /editor command", + ) + + ########## + group = parser.add_argument_group("Voice Settings") + group.add_argument( + "--voice-format", + metavar="VOICE_FORMAT", + default="wav", + choices=["wav", "mp3", "webm"], + help="Audio format for voice recording (default: wav). webm and mp3 require ffmpeg", + ) + group.add_argument( + "--voice-language", + metavar="VOICE_LANGUAGE", + default="en", + help="Specify the language for voice using ISO 639-1 code (default: auto)", + ) return parser @@ -588,7 +785,6 @@ def get_md_help(): parser.formatter_class = MarkdownHelpFormatter return argparse.ArgumentParser.format_help(parser) - return parser.format_help() def get_sample_yaml(): @@ -602,7 +798,6 @@ def get_sample_yaml(): parser.formatter_class = YamlHelpFormatter return argparse.ArgumentParser.format_help(parser) - return parser.format_help() def get_sample_dotenv(): @@ -616,7 +811,6 @@ def get_sample_dotenv(): parser.formatter_class = DotEnvFormatter return argparse.ArgumentParser.format_help(parser) - return parser.format_help() def main(): diff --git a/aider/args_formatter.py b/aider/args_formatter.py index f97cb433d..5b458fec2 100644 --- a/aider/args_formatter.py +++ b/aider/args_formatter.py @@ -144,8 +144,15 @@ class YamlHelpFormatter(argparse.HelpFormatter): if default: parts.append(f"#{switch}: {default}\n") + elif action.nargs in ("*", "+") or isinstance(action, argparse._AppendAction): + parts.append(f"#{switch}: xxx") + parts.append("## Specify multiple values like this:") + parts.append(f"#{switch}:") + parts.append(f"# - xxx") + parts.append(f"# - yyy") + parts.append(f"# - zzz") else: - parts.append(f"#{switch}:\n") + parts.append(f"#{switch}: xxx\n") ### # parts.append(str(action)) diff --git a/aider/coders/__init__.py b/aider/coders/__init__.py index 637dc343c..e9d334bc9 100644 --- a/aider/coders/__init__.py +++ b/aider/coders/__init__.py @@ -1,13 +1,16 @@ +from .architect_coder import ArchitectCoder from .ask_coder import AskCoder from .base_coder import Coder from .editblock_coder import EditBlockCoder from .editblock_fenced_coder import EditBlockFencedCoder +from .editor_editblock_coder import EditorEditBlockCoder +from .editor_whole_coder import EditorWholeFileCoder from .help_coder import HelpCoder - -# from .single_wholefile_func_coder import SingleWholeFileFunctionCoder from .udiff_coder import UnifiedDiffCoder from .wholefile_coder import WholeFileCoder +# from .single_wholefile_func_coder import SingleWholeFileFunctionCoder + __all__ = [ HelpCoder, AskCoder, @@ -17,4 +20,7 @@ __all__ = [ WholeFileCoder, UnifiedDiffCoder, # SingleWholeFileFunctionCoder, + ArchitectCoder, + EditorEditBlockCoder, + EditorWholeFileCoder, ] diff --git a/aider/coders/architect_coder.py b/aider/coders/architect_coder.py new file mode 100644 index 000000000..a561e3e0d --- /dev/null +++ b/aider/coders/architect_coder.py @@ -0,0 +1,47 @@ +from .architect_prompts import ArchitectPrompts +from .ask_coder import AskCoder +from .base_coder import Coder + + +class ArchitectCoder(AskCoder): + edit_format = "architect" + gpt_prompts = ArchitectPrompts() + + def reply_completed(self): + content = self.partial_response_content + + if not content or not content.strip(): + return + + if not self.io.confirm_ask("Edit the files?"): + return + + kwargs = dict() + + # Use the editor_model from the main_model if it exists, otherwise use the main_model itself + editor_model = self.main_model.editor_model or self.main_model + + kwargs["main_model"] = editor_model + kwargs["edit_format"] = self.main_model.editor_edit_format + kwargs["suggest_shell_commands"] = False + kwargs["map_tokens"] = 0 + kwargs["total_cost"] = self.total_cost + kwargs["cache_prompts"] = False + kwargs["num_cache_warming_pings"] = 0 + kwargs["summarize_from_coder"] = False + + new_kwargs = dict(io=self.io, from_coder=self) + new_kwargs.update(kwargs) + + editor_coder = Coder.create(**new_kwargs) + editor_coder.cur_messages = [] + editor_coder.done_messages = [] + + if self.verbose: + editor_coder.show_announcements() + + editor_coder.run(with_message=content, preproc=False) + + self.move_back_cur_messages("I made those changes to the files.") + self.total_cost = editor_coder.total_cost + self.aider_commit_hashes = editor_coder.aider_commit_hashes diff --git a/aider/coders/architect_prompts.py b/aider/coders/architect_prompts.py new file mode 100644 index 000000000..2ac23f5fc --- /dev/null +++ b/aider/coders/architect_prompts.py @@ -0,0 +1,40 @@ +# flake8: noqa: E501 + +from .base_prompts import CoderPrompts + + +class ArchitectPrompts(CoderPrompts): + main_system = """Act as an expert architect engineer and provide direction to your editor engineer. +Study the change request and the current code. +Describe how to modify the code to complete the request. +The editor engineer will rely solely on your instructions, so make them unambiguous and complete. +Explain all needed code changes clearly and completely, but concisely. +Just show the changes needed. + +DO NOT show the entire updated function/file/etc! + +Always reply to the user in {language}. +""" + + example_messages = [] + + files_content_prefix = """I have *added these files to the chat* so you see all of their contents. +*Trust this message as the true contents of the files!* +Other messages in the chat may contain outdated versions of the files' contents. +""" # noqa: E501 + + files_content_assistant_reply = ( + "Ok, I will use that as the true, current contents of the files." + ) + + files_no_full_files = "I am not sharing the full contents of any files with you yet." + + files_no_full_files_with_repo_map = "" + files_no_full_files_with_repo_map_reply = "" + + repo_content_prefix = """I am working with you on code in a git repository. +Here are summaries of some files present in my git repo. +If you need to see the full contents of any files to answer my questions, ask me to *add them to the chat*. +""" + + system_reminder = "" diff --git a/aider/coders/ask_prompts.py b/aider/coders/ask_prompts.py index 98565af0b..198ec6172 100644 --- a/aider/coders/ask_prompts.py +++ b/aider/coders/ask_prompts.py @@ -6,8 +6,7 @@ from .base_prompts import CoderPrompts class AskPrompts(CoderPrompts): main_system = """Act as an expert code analyst. Answer questions about the supplied code. - -Always reply to the user in the same language they are using. +Always reply to the user in {language}. """ example_messages = [] @@ -17,6 +16,10 @@ Always reply to the user in the same language they are using. Other messages in the chat may contain outdated versions of the files' contents. """ # noqa: E501 + files_content_assistant_reply = ( + "Ok, I will use that as the true, current contents of the files." + ) + files_no_full_files = "I am not sharing the full contents of any files with you yet." files_no_full_files_with_repo_map = "" diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index b4d65c609..3926cd987 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -17,27 +17,35 @@ from collections import defaultdict from datetime import datetime from json.decoder import JSONDecodeError from pathlib import Path - -import git -from rich.console import Console, Text -from rich.markdown import Markdown +from typing import List from aider import __version__, models, prompts, urls, utils +from aider.analytics import Analytics from aider.commands import Commands +from aider.exceptions import LiteLLMExceptions from aider.history import ChatSummary -from aider.io import InputOutput +from aider.io import ConfirmGroup, InputOutput from aider.linter import Linter from aider.llm import litellm -from aider.mdstream import MarkdownStream -from aider.repo import GitRepo +from aider.repo import ANY_GIT_ERROR, GitRepo from aider.repomap import RepoMap -from aider.sendchat import retry_exceptions, send_completion -from aider.utils import format_content, format_messages, is_image_file +from aider.run_cmd import run_cmd +from aider.sendchat import RETRY_TIMEOUT, send_completion +from aider.utils import format_content, format_messages, format_tokens, is_image_file from ..dump import dump # noqa: F401 from .chat_chunks import ChatChunks +class UnknownEditFormat(ValueError): + def __init__(self, edit_format, valid_formats): + self.edit_format = edit_format + self.valid_formats = valid_formats + super().__init__( + f"Unknown edit format {edit_format}. Valid formats are: {', '.join(valid_formats)}" + ) + + class MissingAPIKeyError(ValueError): pass @@ -89,6 +97,12 @@ class Coder: message_tokens_sent = 0 message_tokens_received = 0 add_cache_headers = False + cache_warming_thread = None + num_cache_warming_pings = 0 + suggest_shell_commands = True + detect_urls = True + ignore_mentions = None + chat_language = None @classmethod def create( @@ -152,10 +166,17 @@ class Coder: res.original_kwargs = dict(kwargs) return res - raise ValueError(f"Unknown edit format {edit_format}") + valid_formats = [ + str(c.edit_format) + for c in coders.__all__ + if hasattr(c, "edit_format") and c.edit_format is not None + ] + raise UnknownEditFormat(edit_format, valid_formats) def clone(self, **kwargs): - return Coder.create(from_coder=self, **kwargs) + new_coder = Coder.create(from_coder=self, **kwargs) + new_coder.ignore_mentions = self.ignore_mentions + return new_coder def get_announcements(self): lines = [] @@ -171,12 +192,19 @@ class Coder: prefix = "Model" output = f"{prefix}: {main_model.name} with {self.edit_format} edit format" - if self.add_cache_headers: + if self.add_cache_headers or main_model.caches_by_default: output += ", prompt cache" if main_model.info.get("supports_assistant_prefill"): output += ", infinite output" lines.append(output) + if self.edit_format == "architect": + output = ( + f"Editor model: {main_model.editor_model.name} with" + f" {main_model.editor_edit_format} edit format" + ) + lines.append(output) + if weak_model is not main_model: output = f"Weak model: {weak_model.name}" lines.append(output) @@ -185,6 +213,7 @@ class Coder: if self.repo: rel_repo_dir = self.repo.get_rel_repo_dir() num_files = len(self.repo.get_tracked_files()) + lines.append(f"Git repo: {rel_repo_dir} with {num_files:,} files") if num_files > 1000: lines.append( @@ -204,7 +233,7 @@ class Coder: if map_tokens > max_map_tokens: lines.append( f"Warning: map-tokens > {max_map_tokens} is not recommended as too much" - " irrelevant code can confuse GPT." + " irrelevant code can confuse LLMs." ) else: lines.append("Repo-map: disabled because map_tokens == 0") @@ -233,8 +262,6 @@ class Coder: dry_run=False, map_tokens=1024, verbose=False, - assistant_output_color="blue", - code_theme="default", stream=True, use_git=True, cur_messages=None, @@ -249,13 +276,29 @@ class Coder: commands=None, summarizer=None, total_cost=0.0, + analytics=None, map_refresh="auto", cache_prompts=False, + num_cache_warming_pings=0, + suggest_shell_commands=True, + chat_language=None, + detect_urls=True, ): + # Fill in a dummy Analytics if needed, but it is never .enable()'d + self.analytics = analytics if analytics is not None else Analytics() + + self.event = self.analytics.event + self.chat_language = chat_language self.commit_before_message = [] self.aider_commit_hashes = set() self.rejected_urls = set() self.abs_root_path_cache = {} + self.ignore_mentions = set() + + self.suggest_shell_commands = suggest_shell_commands + self.detect_urls = detect_urls + + self.num_cache_warming_pings = num_cache_warming_pings if not fnames: fnames = [] @@ -298,17 +341,10 @@ class Coder: self.auto_commits = auto_commits self.dirty_commits = dirty_commits - self.assistant_output_color = assistant_output_color - self.code_theme = code_theme self.dry_run = dry_run self.pretty = self.io.pretty - if self.pretty: - self.console = Console() - else: - self.console = Console(force_terminal=False, no_color=True) - self.main_model = main_model if cache_prompts and self.main_model.cache_control: @@ -336,20 +372,26 @@ class Coder: for fname in fnames: fname = Path(fname) - if not fname.exists(): - self.io.tool_output(f"Creating empty file {fname}") - fname.parent.mkdir(parents=True, exist_ok=True) - fname.touch() - - if not fname.is_file(): - raise ValueError(f"{fname} is not a file") - - fname = str(fname.resolve()) + if self.repo and self.repo.git_ignored_file(fname): + self.io.tool_warning(f"Skipping {fname} that matches gitignore spec.") if self.repo and self.repo.ignored_file(fname): - self.io.tool_error(f"Skipping {fname} that matches aiderignore spec.") + self.io.tool_warning(f"Skipping {fname} that matches aiderignore spec.") continue + if not fname.exists(): + if utils.touch_file(fname): + self.io.tool_output(f"Creating empty file {fname}") + else: + self.io.tool_warning(f"Can not create {fname}, skipping.") + continue + + if not fname.is_file(): + self.io.tool_warning(f"Skipping {fname} that is not a normal file.") + continue + + fname = str(fname.resolve()) + self.abs_fnames.add(fname) self.check_added_files() @@ -363,7 +405,7 @@ class Coder: if os.path.exists(abs_fname): self.abs_read_only_fnames.add(abs_fname) else: - self.io.tool_error(f"Error: Read-only file {fname} does not exist. Skipping.") + self.io.tool_warning(f"Error: Read-only file {fname} does not exist. Skipping.") if map_tokens is None: use_repo_map = main_model.use_repo_map @@ -406,7 +448,7 @@ class Coder: self.linter = Linter(root=self.root, encoding=io.encoding) self.auto_lint = auto_lint self.setup_lint_cmds(lint_cmds) - + self.lint_cmds = lint_cmds self.auto_test = auto_test self.test_cmd = test_cmd @@ -472,7 +514,7 @@ class Coder: if content is None: relative_fname = self.get_rel_fname(fname) - self.io.tool_error(f"Dropping {relative_fname} from the chat.") + self.io.tool_warning(f"Dropping {relative_fname} from the chat.") self.abs_fnames.remove(fname) else: yield fname, content @@ -486,9 +528,10 @@ class Coder: if content is not None: all_content += content + "\n" + lines = all_content.splitlines() good = False for fence_open, fence_close in self.fences: - if fence_open in all_content or fence_close in all_content: + if any(line.startswith(fence_open) or line.startswith(fence_close) for line in lines): continue good = True break @@ -497,7 +540,7 @@ class Coder: self.fence = (fence_open, fence_close) else: self.fence = self.fences[0] - self.io.tool_error( + self.io.tool_warning( "Unable to find a fencing strategy! Falling back to:" f" {self.fence[0]}...{self.fence[1]}" ) @@ -622,6 +665,8 @@ class Coder: def get_readonly_files_messages(self): readonly_messages = [] + + # Handle non-image files read_only_content = self.get_read_only_files_content() if read_only_content: readonly_messages += [ @@ -633,6 +678,15 @@ class Coder: content="Ok, I will use these files as references.", ), ] + + # Handle image files + images_message = self.get_images_message(self.abs_read_only_fnames) + if images_message is not None: + readonly_messages += [ + images_message, + dict(role="assistant", content="Ok, I will use these images as references."), + ] + return readonly_messages def get_chat_files_messages(self): @@ -640,7 +694,7 @@ class Coder: if self.abs_fnames: files_content = self.gpt_prompts.files_content_prefix files_content += self.get_files_content() - files_reply = "Ok, any changes I propose will be to those files." + files_reply = self.gpt_prompts.files_content_assistant_reply elif self.get_repo_map() and self.gpt_prompts.files_no_full_files_with_repo_map: files_content = self.gpt_prompts.files_no_full_files_with_repo_map files_reply = self.gpt_prompts.files_no_full_files_with_repo_map_reply @@ -654,7 +708,7 @@ class Coder: dict(role="assistant", content=files_reply), ] - images_message = self.get_images_message() + images_message = self.get_images_message(self.abs_fnames) if images_message is not None: chat_files_messages += [ images_message, @@ -663,23 +717,42 @@ class Coder: return chat_files_messages - def get_images_message(self): - if not self.main_model.accepts_images: + def get_images_message(self, fnames): + supports_images = self.main_model.info.get("supports_vision") + supports_pdfs = self.main_model.info.get("supports_pdf_input") or self.main_model.info.get( + "max_pdf_size_mb" + ) + + # https://github.com/BerriAI/litellm/pull/6928 + supports_pdfs = supports_pdfs or "claude-3-5-sonnet-20241022" in self.main_model.name + + if not (supports_images or supports_pdfs): return None image_messages = [] - for fname, content in self.get_abs_fnames_content(): - if is_image_file(fname): - with open(fname, "rb") as image_file: - encoded_string = base64.b64encode(image_file.read()).decode("utf-8") - mime_type, _ = mimetypes.guess_type(fname) - if mime_type and mime_type.startswith("image/"): - image_url = f"data:{mime_type};base64,{encoded_string}" - rel_fname = self.get_rel_fname(fname) - image_messages += [ - {"type": "text", "text": f"Image file: {rel_fname}"}, - {"type": "image_url", "image_url": {"url": image_url, "detail": "high"}}, - ] + for fname in fnames: + if not is_image_file(fname): + continue + + mime_type, _ = mimetypes.guess_type(fname) + if not mime_type: + continue + + with open(fname, "rb") as image_file: + encoded_string = base64.b64encode(image_file.read()).decode("utf-8") + image_url = f"data:{mime_type};base64,{encoded_string}" + rel_fname = self.get_rel_fname(fname) + + if mime_type.startswith("image/") and supports_images: + image_messages += [ + {"type": "text", "text": f"Image file: {rel_fname}"}, + {"type": "image_url", "image_url": {"url": image_url, "detail": "high"}}, + ] + elif mime_type == "application/pdf" and supports_pdfs: + image_messages += [ + {"type": "text", "text": f"PDF file: {rel_fname}"}, + {"type": "image_url", "image_url": image_url}, + ] if not image_messages: return None @@ -700,7 +773,7 @@ class Coder: self.shell_commands = [] if self.repo: - self.commit_before_message.append(self.repo.get_head()) + self.commit_before_message.append(self.repo.get_head_commit_sha()) def run(self, with_message=None, preproc=True): try: @@ -741,7 +814,7 @@ class Coder: return self.commands.run(inp) self.check_for_file_mentions(inp) - self.check_for_urls(inp) + inp = self.check_for_urls(inp) return inp @@ -761,36 +834,59 @@ class Coder: break if self.num_reflections >= self.max_reflections: - self.io.tool_error(f"Only {self.max_reflections} reflections allowed, stopping.") + self.io.tool_warning(f"Only {self.max_reflections} reflections allowed, stopping.") return self.num_reflections += 1 message = self.reflected_message - def check_for_urls(self, inp): + def check_and_open_urls(self, exc, friendly_msg=None): + """Check exception for URLs, offer to open in a browser, with user-friendly error msgs.""" + text = str(exc) + + if friendly_msg: + self.io.tool_warning(text) + self.io.tool_error(f"{friendly_msg}") + else: + self.io.tool_error(text) + + url_pattern = re.compile(r"(https?://[^\s/$.?#].[^\s]*)") + urls = list(set(url_pattern.findall(text))) # Use set to remove duplicates + for url in urls: + url = url.rstrip(".',\"") + self.io.offer_url(url) + return urls + + def check_for_urls(self, inp: str) -> List[str]: + """Check input for URLs and offer to add them to the chat.""" + if not self.detect_urls: + return inp + url_pattern = re.compile(r"(https?://[^\s/$.?#].[^\s]*[^\s,.])") urls = list(set(url_pattern.findall(inp))) # Use set to remove duplicates - added_urls = [] + group = ConfirmGroup(urls) for url in urls: if url not in self.rejected_urls: - if self.io.confirm_ask("Add URL to the chat?", subject=url): + url = url.rstrip(".',\"") + if self.io.confirm_ask( + "Add URL to the chat?", subject=url, group=group, allow_never=True + ): inp += "\n\n" - inp += self.commands.cmd_web(url, paginate=False) - added_urls.append(url) + inp += self.commands.cmd_web(url, return_content=True) else: self.rejected_urls.add(url) - return added_urls + return inp def keyboard_interrupt(self): now = time.time() thresh = 2 # seconds if self.last_keyboard_interrupt and now - self.last_keyboard_interrupt < thresh: - self.io.tool_error("\n\n^C KeyboardInterrupt") + self.io.tool_warning("\n\n^C KeyboardInterrupt") sys.exit() - self.io.tool_error("\n\n^C again to exit") + self.io.tool_warning("\n\n^C again to exit") self.last_keyboard_interrupt = now @@ -810,7 +906,7 @@ class Coder: try: self.summarized_done_messages = self.summarizer.summarize(self.done_messages) except ValueError as err: - self.io.tool_error(err.args[0]) + self.io.tool_warning(err.args[0]) if self.verbose: self.io.tool_output("Finished summarizing chat history.") @@ -838,6 +934,9 @@ class Coder: self.cur_messages = [] def get_user_language(self): + if self.chat_language: + return self.chat_language + try: lang = locale.getlocale()[0] if lang: @@ -854,29 +953,72 @@ class Coder: return None - def fmt_system_prompt(self, prompt): - lazy_prompt = self.gpt_prompts.lazy_prompt if self.main_model.lazy else "" - + def get_platform_info(self): platform_text = f"- Platform: {platform.platform()}\n" - if os.name == "nt": - var = "COMSPEC" - else: - var = "SHELL" - - val = os.getenv(var) - platform_text += f"- Shell: {var}={val}\n" + shell_var = "COMSPEC" if os.name == "nt" else "SHELL" + shell_val = os.getenv(shell_var) + platform_text += f"- Shell: {shell_var}={shell_val}\n" user_lang = self.get_user_language() if user_lang: platform_text += f"- Language: {user_lang}\n" dt = datetime.now().astimezone().strftime("%Y-%m-%d") - platform_text += f"- Current date: {dt}" + platform_text += f"- Current date: {dt}\n" + + if self.repo: + platform_text += "- The user is operating inside a git repository\n" + + if self.lint_cmds: + if self.auto_lint: + platform_text += ( + "- The user's pre-commit runs these lint commands, don't suggest running" + " them:\n" + ) + else: + platform_text += "- The user prefers these lint commands:\n" + for lang, cmd in self.lint_cmds.items(): + if lang is None: + platform_text += f" - {cmd}\n" + else: + platform_text += f" - {lang}: {cmd}\n" + + if self.test_cmd: + if self.auto_test: + platform_text += ( + "- The user's pre-commit runs this test command, don't suggest running them: " + ) + else: + platform_text += "- The user prefers this test command: " + platform_text += self.test_cmd + "\n" + + return platform_text + + def fmt_system_prompt(self, prompt): + lazy_prompt = self.gpt_prompts.lazy_prompt if self.main_model.lazy else "" + platform_text = self.get_platform_info() + + if self.suggest_shell_commands: + shell_cmd_prompt = self.gpt_prompts.shell_cmd_prompt.format(platform=platform_text) + shell_cmd_reminder = self.gpt_prompts.shell_cmd_reminder.format(platform=platform_text) + else: + shell_cmd_prompt = self.gpt_prompts.no_shell_cmd_prompt.format(platform=platform_text) + shell_cmd_reminder = self.gpt_prompts.no_shell_cmd_reminder.format( + platform=platform_text + ) + + if self.chat_language: + language = self.chat_language + else: + language = "the same language they are using" prompt = prompt.format( fence=self.fence, lazy_prompt=lazy_prompt, platform=platform_text, + shell_cmd_prompt=shell_cmd_prompt, + shell_cmd_reminder=shell_cmd_reminder, + language=language, ) return prompt @@ -918,9 +1060,16 @@ class Coder: chunks = ChatChunks() - chunks.system = [ - dict(role="system", content=main_sys), - ] + if self.main_model.use_system_prompt: + chunks.system = [ + dict(role="system", content=main_sys), + ] + else: + chunks.system = [ + dict(role="user", content=main_sys), + dict(role="assistant", content="Ok."), + ] + chunks.examples = example_messages self.summarize_end() @@ -958,7 +1107,7 @@ class Coder: max_input_tokens = self.main_model.info.get("max_input_tokens") or 0 # Add the reminder prompt if we still have room to include it. if ( - max_input_tokens is None + not max_input_tokens or total_tokens < max_input_tokens and self.gpt_prompts.system_reminder ): @@ -980,28 +1129,83 @@ class Coder: if self.add_cache_headers: chunks.add_cache_control_headers() - msgs = chunks.all_messages() - return msgs + return chunks + + def warm_cache(self, chunks): + if not self.add_cache_headers: + return + if not self.num_cache_warming_pings: + return + + delay = 5 * 60 - 5 + self.next_cache_warm = time.time() + delay + self.warming_pings_left = self.num_cache_warming_pings + self.cache_warming_chunks = chunks + + if self.cache_warming_thread: + return + + def warm_cache_worker(): + while True: + time.sleep(1) + if self.warming_pings_left <= 0: + continue + now = time.time() + if now < self.next_cache_warm: + continue + + self.warming_pings_left -= 1 + self.next_cache_warm = time.time() + delay + + kwargs = dict(self.main_model.extra_params) or dict() + kwargs["max_tokens"] = 1 + + try: + completion = litellm.completion( + model=self.main_model.name, + messages=self.cache_warming_chunks.cacheable_messages(), + stream=False, + **kwargs, + ) + except Exception as err: + self.io.tool_warning(f"Cache warming error: {str(err)}") + continue + + cache_hit_tokens = getattr( + completion.usage, "prompt_cache_hit_tokens", 0 + ) or getattr(completion.usage, "cache_read_input_tokens", 0) + + if self.verbose: + self.io.tool_output(f"Warmed {format_tokens(cache_hit_tokens)} cached tokens.") + + self.cache_warming_thread = threading.Timer(0, warm_cache_worker) + self.cache_warming_thread.daemon = True + self.cache_warming_thread.start() + + return chunks def send_message(self, inp): self.cur_messages += [ dict(role="user", content=inp), ] - messages = self.format_messages() + chunks = self.format_messages() + messages = chunks.all_messages() + self.warm_cache(chunks) if self.verbose: utils.show_messages(messages, functions=self.functions) self.multi_response_content = "" if self.show_pretty() and self.stream: - mdargs = dict(style=self.assistant_output_color, code_theme=self.code_theme) - self.mdstream = MarkdownStream(mdargs=mdargs) + self.mdstream = self.io.get_assistant_mdstream() else: self.mdstream = None retry_delay = 0.125 + litellm_ex = LiteLLMExceptions() + self.usage_report = None exhausted = False interrupted = False @@ -1010,24 +1214,37 @@ class Coder: try: yield from self.send(messages, functions=self.functions) break - except retry_exceptions() as err: - self.io.tool_error(str(err)) - retry_delay *= 2 - if retry_delay > 60: + except litellm_ex.exceptions_tuple() as err: + ex_info = litellm_ex.get_ex_info(err) + + if ex_info.name == "ContextWindowExceededError": + exhausted = True break + + should_retry = ex_info.retry + if should_retry: + retry_delay *= 2 + if retry_delay > RETRY_TIMEOUT: + should_retry = False + + if not should_retry: + self.mdstream = None + self.check_and_open_urls(err, ex_info.description) + break + + err_msg = str(err) + if ex_info.description: + self.io.tool_warning(err_msg) + self.io.tool_error(ex_info.description) + else: + self.io.tool_error(err_msg) + self.io.tool_output(f"Retrying in {retry_delay:.1f} seconds...") time.sleep(retry_delay) continue except KeyboardInterrupt: interrupted = True break - except litellm.ContextWindowExceededError: - # The input is overflowing the context window! - exhausted = True - break - except litellm.exceptions.BadRequestError as br_err: - self.io.tool_error(f"BadRequestError: {br_err}") - return except FinishReasonLength: # We hit the output limit! if not self.main_model.info.get("supports_assistant_prefill"): @@ -1043,9 +1260,10 @@ class Coder: dict(role="assistant", content=self.multi_response_content, prefix=True) ) except Exception as err: - self.io.tool_error(f"Unexpected error: {err}") + self.mdstream = None lines = traceback.format_exception(type(err), err, err.__traceback__) - self.io.tool_error("".join(lines)) + self.io.tool_warning("".join(lines)) + self.io.tool_error(str(err)) return finally: if self.mdstream: @@ -1075,6 +1293,20 @@ class Coder: else: content = "" + if not interrupted: + add_rel_files_message = self.check_for_file_mentions(content) + if add_rel_files_message: + if self.reflected_message: + self.reflected_message += "\n\n" + add_rel_files_message + else: + self.reflected_message = add_rel_files_message + return + + try: + self.reply_completed() + except KeyboardInterrupt: + interrupted = True + if interrupted: content += "\n^C KeyboardInterrupt" self.cur_messages += [dict(role="assistant", content=content)] @@ -1107,7 +1339,12 @@ class Coder: self.update_cur_messages() return - self.run_shell_commands() + shared_output = self.run_shell_commands() + if shared_output: + self.cur_messages += [ + dict(role="user", content=shared_output), + dict(role="assistant", content="Ok"), + ] if edited and self.auto_test: test_errors = self.commands.cmd_test(self.test_cmd) @@ -1119,12 +1356,8 @@ class Coder: self.update_cur_messages() return - add_rel_files_message = self.check_for_file_mentions(content) - if add_rel_files_message: - if self.reflected_message: - self.reflected_message += "\n\n" + add_rel_files_message - else: - self.reflected_message = add_rel_files_message + def reply_completed(self): + pass def show_exhausted_error(self): output_tokens = 0 @@ -1132,7 +1365,7 @@ class Coder: output_tokens = self.main_model.token_count(self.partial_response_content) max_output_tokens = self.main_model.info.get("max_output_tokens") or 0 - input_tokens = self.main_model.token_count(self.format_messages()) + input_tokens = self.main_model.token_count(self.format_messages().all_messages()) max_input_tokens = self.main_model.info.get("max_input_tokens") or 0 total_tokens = input_tokens + output_tokens @@ -1165,9 +1398,7 @@ class Coder: res.append("- Ask for smaller changes in each request.") res.append("- Break your code into smaller source files.") if "diff" not in self.main_model.edit_format: - res.append( - "- Use a stronger model like gpt-4o, sonnet or opus that can return diffs." - ) + res.append("- Use a stronger model that can return diffs.") if input_tokens >= max_input_tokens or total_tokens >= max_input_tokens: res.append("") @@ -1177,11 +1408,9 @@ class Coder: res.append("- Use /clear to clear the chat history.") res.append("- Break your code into smaller source files.") - res.append("") - res.append(f"For more info: {urls.token_limits}") - res = "".join([line + "\n" for line in res]) self.io.tool_error(res) + self.io.offer_url(urls.token_limits) def lint_edited(self, fnames): res = "" @@ -1194,7 +1423,7 @@ class Coder: res += "\n" if res: - self.io.tool_error(res) + self.io.tool_warning(res) return res @@ -1222,9 +1451,18 @@ class Coder: addable_rel_fnames = self.get_addable_relative_files() + # Get basenames of files already in chat or read-only + existing_basenames = {os.path.basename(f) for f in self.get_inchat_relative_files()} | { + os.path.basename(self.get_rel_fname(f)) for f in self.abs_read_only_fnames + } + mentioned_rel_fnames = set() fname_to_rel_fnames = {} for rel_fname in addable_rel_fnames: + # Skip files that share a basename with files already in chat + if os.path.basename(rel_fname) in existing_basenames: + continue + normalized_rel_fname = rel_fname.replace("\\", "/") normalized_words = set(word.replace("\\", "/") for word in words) if normalized_rel_fname in normalized_words: @@ -1247,17 +1485,22 @@ class Coder: def check_for_file_mentions(self, content): mentioned_rel_fnames = self.get_file_mentions(content) - if not mentioned_rel_fnames: + new_mentions = mentioned_rel_fnames - self.ignore_mentions + + if not new_mentions: return - add_files = "\n".join(mentioned_rel_fnames) + "\n" - if not self.io.confirm_ask("Add these files to the chat?", subject=add_files): - return + added_fnames = [] + group = ConfirmGroup(new_mentions) + for rel_fname in sorted(new_mentions): + if self.io.confirm_ask(f"Add {rel_fname} to the chat?", group=group, allow_never=True): + self.add_rel_fname(rel_fname) + added_fnames.append(rel_fname) + else: + self.ignore_mentions.add(rel_fname) - for rel_fname in mentioned_rel_fnames: - self.add_rel_fname(rel_fname) - - return prompts.added_files.format(fnames=", ".join(mentioned_rel_fnames)) + if added_fnames: + return prompts.added_files.format(fnames=", ".join(added_fnames)) def send(self, messages, model=None, functions=None): if not model: @@ -1268,6 +1511,11 @@ class Coder: self.io.log_llm_history("TO LLM", format_messages(messages)) + if self.main_model.use_temperature: + temp = self.temperature + else: + temp = None + completion = None try: hash_object, completion = send_completion( @@ -1275,9 +1523,8 @@ class Coder: messages, functions, self.stream, - self.temperature, - extra_headers=model.extra_headers, - max_tokens=model.max_tokens, + temp, + extra_params=model.extra_params, ) self.chat_completion_call_hashes.append(hash_object.hexdigest()) @@ -1340,14 +1587,7 @@ class Coder: raise Exception("No data found in LLM response!") show_resp = self.render_incremental_response(True) - if self.show_pretty(): - show_resp = Markdown( - show_resp, style=self.assistant_output_color, code_theme=self.code_theme - ) - else: - show_resp = Text(show_resp or "") - - self.io.console.print(show_resp) + self.io.assistant_output(show_resp, pretty=self.show_pretty()) if ( hasattr(completion.choices[0], "finish_reason") @@ -1423,7 +1663,6 @@ class Coder: completion.usage, "cache_creation_input_tokens" ): self.message_tokens_sent += prompt_tokens - self.message_tokens_sent += cache_hit_tokens self.message_tokens_sent += cache_write_tokens else: self.message_tokens_sent += prompt_tokens @@ -1435,14 +1674,6 @@ class Coder: self.message_tokens_received += completion_tokens - def format_tokens(count): - if count < 1000: - return f"{count}" - elif count < 10000: - return f"{count / 1000:.1f}k" - else: - return f"{round(count / 1000)}k" - tokens_report = f"Tokens: {format_tokens(self.message_tokens_sent)} sent" if cache_write_tokens: @@ -1513,11 +1744,27 @@ class Coder: self.usage_report = tokens_report + sep + cost_report def show_usage_report(self): - if self.usage_report: - self.io.tool_output(self.usage_report) - self.message_cost = 0.0 - self.message_tokens_sent = 0 - self.message_tokens_received = 0 + if not self.usage_report: + return + + self.io.tool_output(self.usage_report) + + prompt_tokens = self.message_tokens_sent + completion_tokens = self.message_tokens_received + self.event( + "message_send", + main_model=self.main_model, + edit_format=self.edit_format, + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=prompt_tokens + completion_tokens, + cost=self.message_cost, + total_cost=self.total_cost, + ) + + self.message_cost = 0.0 + self.message_tokens_sent = 0 + self.message_tokens_received = 0 def get_multi_response_content(self, final=False): cur = self.multi_response_content or "" @@ -1528,7 +1775,10 @@ class Coder: return cur + new def get_rel_fname(self, fname): - return os.path.relpath(fname, self.root) + try: + return os.path.relpath(fname, self.root) + except ValueError: + return fname def get_inchat_relative_files(self): files = [self.get_rel_fname(fname) for fname in self.abs_fnames] @@ -1589,14 +1839,19 @@ class Coder: self.check_for_dirty_commit(path) return True + if self.repo and self.repo.git_ignored_file(path): + self.io.tool_warning(f"Skipping edits to {path} that matches gitignore spec.") + return + if not Path(full_path).exists(): if not self.io.confirm_ask("Create new file?", subject=path): - self.io.tool_error(f"Skipping edits to {path}") + self.io.tool_output(f"Skipping edits to {path}") return if not self.dry_run: - Path(full_path).parent.mkdir(parents=True, exist_ok=True) - Path(full_path).touch() + if not utils.touch_file(full_path): + self.io.tool_error(f"Unable to create {path}, skipping edits.") + return # Seems unlikely that we needed to create the file, but it was # actually already part of the repo. @@ -1612,7 +1867,7 @@ class Coder: "Allow edits to file that has not been added to the chat?", subject=path, ): - self.io.tool_error(f"Skipping edits to {path}") + self.io.tool_output(f"Skipping edits to {path}") return if need_to_add: @@ -1647,8 +1902,8 @@ class Coder: if tokens < warn_number_of_tokens: return - self.io.tool_error("Warning: it's best to only add files that need changes to the chat.") - self.io.tool_error(urls.edit_errors) + self.io.tool_warning("Warning: it's best to only add files that need changes to the chat.") + self.io.tool_warning(urls.edit_errors) self.warning_given = True def prepare_to_edit(self, edits): @@ -1679,10 +1934,13 @@ class Coder: return res def apply_updates(self): + edited = set() try: edits = self.get_edits() + edits = self.apply_edits_dry_run(edits) edits = self.prepare_to_edit(edits) edited = set(edit[0] for edit in edits) + self.apply_edits(edits) except ValueError as err: self.num_malformed_responses += 1 @@ -1690,14 +1948,14 @@ class Coder: err = err.args[0] self.io.tool_error("The LLM did not conform to the edit format.") - self.io.tool_error(urls.edit_errors) - self.io.tool_error() - self.io.tool_error(str(err), strip=False) + self.io.tool_output(urls.edit_errors) + self.io.tool_output() + self.io.tool_output(str(err)) self.reflected_message = str(err) return edited - except git.exc.GitCommandError as err: + except ANY_GIT_ERROR as err: self.io.tool_error(str(err)) return edited except Exception as err: @@ -1761,17 +2019,20 @@ class Coder: if not context: context = self.get_context_from_history(self.cur_messages) - res = self.repo.commit(fnames=edited, context=context, aider_edits=True) - if res: - self.show_auto_commit_outcome(res) - commit_hash, commit_message = res - return self.gpt_prompts.files_content_gpt_edits.format( - hash=commit_hash, - message=commit_message, - ) + try: + res = self.repo.commit(fnames=edited, context=context, aider_edits=True) + if res: + self.show_auto_commit_outcome(res) + commit_hash, commit_message = res + return self.gpt_prompts.files_content_gpt_edits.format( + hash=commit_hash, + message=commit_message, + ) - self.io.tool_output("No changes made to git tracked files.") - return self.gpt_prompts.files_content_gpt_no_edits + return self.gpt_prompts.files_content_gpt_no_edits + except ANY_GIT_ERROR as err: + self.io.tool_error(f"Unable to commit: {str(err)}") + return def show_auto_commit_outcome(self, res): commit_hash, commit_message = res @@ -1784,7 +2045,7 @@ class Coder: def show_undo_hint(self): if not self.commit_before_message: return - if self.commit_before_message[-1] != self.repo.get_head(): + if self.commit_before_message[-1] != self.repo.get_head_commit_sha(): self.io.tool_output("You can use /undo to undo and discard each aider commit.") def dirty_commit(self): @@ -1807,23 +2068,41 @@ class Coder: def apply_edits(self, edits): return + def apply_edits_dry_run(self, edits): + return edits + def run_shell_commands(self): + if not self.suggest_shell_commands: + return "" + done = set() + group = ConfirmGroup(set(self.shell_commands)) + accumulated_output = "" for command in self.shell_commands: if command in done: continue done.add(command) - self.handle_shell_commands(command) + output = self.handle_shell_commands(command, group) + if output: + accumulated_output += output + "\n\n" + return accumulated_output - def handle_shell_commands(self, commands_str): + def handle_shell_commands(self, commands_str, group): commands = commands_str.strip().splitlines() command_count = sum( 1 for cmd in commands if cmd.strip() and not cmd.strip().startswith("#") ) prompt = "Run shell command?" if command_count == 1 else "Run shell commands?" - if not self.io.confirm_ask(prompt, subject="\n".join(commands), explicit_yes_required=True): + if not self.io.confirm_ask( + prompt, + subject="\n".join(commands), + explicit_yes_required=True, + group=group, + allow_never=True, + ): return + accumulated_output = "" for command in commands: command = command.strip() if not command or command.startswith("#"): @@ -1833,6 +2112,14 @@ class Coder: self.io.tool_output(f"Running {command}") # Add the command to input history self.io.add_to_input_history(f"/run {command.strip()}") - result = self.run_interactive_subprocess(command) - if result and result.stdout: - self.io.tool_output(result.stdout) + exit_status, output = run_cmd(command, error_print=self.io.tool_error, cwd=self.root) + if output: + accumulated_output += f"Output from {command}\n{output}\n" + + if accumulated_output.strip() and self.io.confirm_ask( + "Add command output to the chat?", allow_never=True + ): + num_lines = len(accumulated_output.strip().splitlines()) + line_plural = "line" if num_lines == 1 else "lines" + self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.") + return accumulated_output diff --git a/aider/coders/base_prompts.py b/aider/coders/base_prompts.py index d4e91b5e0..c431c7520 100644 --- a/aider/coders/base_prompts.py +++ b/aider/coders/base_prompts.py @@ -22,6 +22,8 @@ You always COMPLETELY IMPLEMENT the needed code! Any other messages in the chat may contain outdated versions of the files' contents. """ # noqa: E501 + files_content_assistant_reply = "Ok, any changes I propose will be to those files." + files_no_full_files = "I am not sharing any files that you can edit yet." files_no_full_files_with_repo_map = """Don't try and edit any existing code without asking me to add the files to the chat! @@ -43,3 +45,8 @@ If you need to edit any of these files, ask me to *add them to the chat* first. read_only_files_prefix = """Here are some READ ONLY files, provided for your reference. Do not edit these files! """ + + shell_cmd_prompt = "" + shell_cmd_reminder = "" + no_shell_cmd_prompt = "" + no_shell_cmd_reminder = "" diff --git a/aider/coders/chat_chunks.py b/aider/coders/chat_chunks.py index 9d1360604..060099a61 100644 --- a/aider/coders/chat_chunks.py +++ b/aider/coders/chat_chunks.py @@ -31,10 +31,12 @@ class ChatChunks: else: self.add_cache_control(self.system) - if self.readonly_files: - self.add_cache_control(self.readonly_files) - else: + if self.repo: + # this will mark both the readonly_files and repomap chunk as cacheable self.add_cache_control(self.repo) + else: + # otherwise, just cache readonly_files if there are any + self.add_cache_control(self.readonly_files) self.add_cache_control(self.chat_files) @@ -51,3 +53,12 @@ class ChatChunks: content["cache_control"] = {"type": "ephemeral"} messages[-1]["content"] = [content] + + def cacheable_messages(self): + messages = self.all_messages() + for i, message in enumerate(reversed(messages)): + if isinstance(message.get("content"), list) and message["content"][0].get( + "cache_control" + ): + return messages[: len(messages) - i] + return messages diff --git a/aider/coders/editblock_coder.py b/aider/coders/editblock_coder.py index 71a344a5c..ecd94e47a 100644 --- a/aider/coders/editblock_coder.py +++ b/aider/coders/editblock_coder.py @@ -1,7 +1,6 @@ import difflib import math import re -import subprocess import sys from difflib import SequenceMatcher from pathlib import Path @@ -23,55 +22,60 @@ class EditBlockCoder(Coder): content = self.partial_response_content # might raise ValueError for malformed ORIG/UPD blocks - edits = list(find_original_update_blocks(content, self.fence)) + edits = list( + find_original_update_blocks( + content, + self.fence, + self.get_inchat_relative_files(), + ) + ) self.shell_commands += [edit[1] for edit in edits if edit[0] is None] edits = [edit for edit in edits if edit[0] is not None] return edits - def run_interactive_subprocess(self, command): - try: - result = subprocess.run( - command, - text=True, - shell=True, - encoding=self.io.encoding, - errors="replace", - ) - if result.returncode == 0: - return - self.io.tool_error(f"Command '{command}' exited with status {result.returncode}") - except Exception as e: - self.io.tool_error(f"Error running command '{command}': {str(e)}") + def apply_edits_dry_run(self, edits): + return self.apply_edits(edits, dry_run=True) - self.io.tool_output(f"To retry and share output with the LLM: /run {command}") - self.io.tool_output("You can find this command in your input history with up-arrow.") - - def apply_edits(self, edits): + def apply_edits(self, edits, dry_run=False): failed = [] passed = [] + updated_edits = [] for edit in edits: path, original, updated = edit full_path = self.abs_root_path(path) - content = self.io.read_text(full_path) - new_content = do_replace(full_path, content, original, updated, self.fence) - if not new_content: + new_content = None + + if Path(full_path).exists(): + content = self.io.read_text(full_path) + new_content = do_replace(full_path, content, original, updated, self.fence) + + # If the edit failed, and + # this is not a "create a new file" with an empty original... + # https://github.com/Aider-AI/aider/issues/2258 + if not new_content and original.strip(): # try patching any of the other files in the chat - dump(self.abs_fnames) for full_path in self.abs_fnames: content = self.io.read_text(full_path) new_content = do_replace(full_path, content, original, updated, self.fence) if new_content: + path = self.get_rel_fname(full_path) break + updated_edits.append((path, original, updated)) + if new_content: - self.io.write_text(full_path, new_content) + if not dry_run: + self.io.write_text(full_path, new_content) passed.append(edit) else: failed.append(edit) + if dry_run: + return updated_edits + if not failed: return @@ -379,9 +383,13 @@ def do_replace(fname, content, before_text, after_text, fence=None): return new_content -HEAD = "<<<<<<< SEARCH" -DIVIDER = "=======" -UPDATED = ">>>>>>> REPLACE" +HEAD = r"^<{5,9} SEARCH\s*$" +DIVIDER = r"^={5,9}\s*$" +UPDATED = r"^>{5,9} REPLACE\s*$" + +HEAD_ERR = "<<<<<<< SEARCH" +DIVIDER_ERR = "=======" +UPDATED_ERR = ">>>>>>> REPLACE" separators = "|".join([HEAD, DIVIDER, UPDATED]) @@ -409,16 +417,22 @@ def strip_filename(filename, fence): filename = filename.strip() filename = filename.strip("`") filename = filename.strip("*") - filename = filename.replace("\\_", "_") + + # https://github.com/Aider-AI/aider/issues/1158 + # filename = filename.replace("\\_", "_") return filename -def find_original_update_blocks(content, fence=DEFAULT_FENCE): +def find_original_update_blocks(content, fence=DEFAULT_FENCE, valid_fnames=None): lines = content.splitlines(keepends=True) i = 0 current_filename = None + head_pattern = re.compile(HEAD) + divider_pattern = re.compile(DIVIDER) + updated_pattern = re.compile(UPDATED) + while i < len(lines): line = lines[i] @@ -437,7 +451,7 @@ def find_original_update_blocks(content, fence=DEFAULT_FENCE): "```csh", "```tcsh", ] - next_is_editblock = i + 1 < len(lines) and lines[i + 1].rstrip() == HEAD + next_is_editblock = i + 1 < len(lines) and head_pattern.match(lines[i + 1].strip()) if any(line.strip().startswith(start) for start in shell_starts) and not next_is_editblock: shell_content = [] @@ -452,9 +466,14 @@ def find_original_update_blocks(content, fence=DEFAULT_FENCE): continue # Check for SEARCH/REPLACE blocks - if line.strip() == HEAD: + if head_pattern.match(line.strip()): try: - filename = find_filename(lines[max(0, i - 3) : i], fence) + # if next line after HEAD exists and is DIVIDER, it's a new file + if i + 1 < len(lines) and divider_pattern.match(lines[i + 1].strip()): + filename = find_filename(lines[max(0, i - 3) : i], fence, None) + else: + filename = find_filename(lines[max(0, i - 3) : i], fence, valid_fnames) + if not filename: if current_filename: filename = current_filename @@ -465,21 +484,27 @@ def find_original_update_blocks(content, fence=DEFAULT_FENCE): original_text = [] i += 1 - while i < len(lines) and not lines[i].strip() == DIVIDER: + while i < len(lines) and not divider_pattern.match(lines[i].strip()): original_text.append(lines[i]) i += 1 - if i >= len(lines) or lines[i].strip() != DIVIDER: - raise ValueError(f"Expected `{DIVIDER}`") + if i >= len(lines) or not divider_pattern.match(lines[i].strip()): + raise ValueError(f"Expected `{DIVIDER_ERR}`") updated_text = [] i += 1 - while i < len(lines) and not lines[i].strip() in (UPDATED, DIVIDER): + while i < len(lines) and not ( + updated_pattern.match(lines[i].strip()) + or divider_pattern.match(lines[i].strip()) + ): updated_text.append(lines[i]) i += 1 - if i >= len(lines) or lines[i].strip() not in (UPDATED, DIVIDER): - raise ValueError(f"Expected `{UPDATED}` or `{DIVIDER}`") + if i >= len(lines) or not ( + updated_pattern.match(lines[i].strip()) + or divider_pattern.match(lines[i].strip()) + ): + raise ValueError(f"Expected `{UPDATED_ERR}` or `{DIVIDER_ERR}`") yield filename, "".join(original_text), "".join(updated_text) @@ -491,7 +516,7 @@ def find_original_update_blocks(content, fence=DEFAULT_FENCE): i += 1 -def find_filename(lines, fence): +def find_filename(lines, fence, valid_fnames): """ Deepseek Coder v2 has been doing this: @@ -505,19 +530,54 @@ def find_filename(lines, fence): This is a more flexible search back for filenames. """ + + if valid_fnames is None: + valid_fnames = [] + # Go back through the 3 preceding lines lines.reverse() lines = lines[:3] + filenames = [] for line in lines: # If we find a filename, done filename = strip_filename(line, fence) if filename: - return filename + filenames.append(filename) # Only continue as long as we keep seeing fences if not line.startswith(fence[0]): - return + break + + if not filenames: + return + + # pick the *best* filename found + + # Check for exact match first + for fname in filenames: + if fname in valid_fnames: + return fname + + # Check for partial match (basename match) + for fname in filenames: + for vfn in valid_fnames: + if fname == Path(vfn).name: + return vfn + + # Perform fuzzy matching with valid_fnames + for fname in filenames: + close_matches = difflib.get_close_matches(fname, valid_fnames, n=1, cutoff=0.8) + if len(close_matches) == 1: + return close_matches[0] + + # If no fuzzy match, look for a file w/extension + for fname in filenames: + if "." in fname: + return fname + + if filenames: + return filenames[0] def find_similar_lines(search_lines, content_lines, threshold=0.6): diff --git a/aider/coders/editblock_func_coder.py b/aider/coders/editblock_func_coder.py index 42bbb20f3..27aa53f11 100644 --- a/aider/coders/editblock_func_coder.py +++ b/aider/coders/editblock_func_coder.py @@ -111,9 +111,9 @@ class EditBlockFunctionCoder(Coder): updated = get_arg(edit, "updated_lines") # gpt-3.5 returns lists even when instructed to return a string! - if self.code_format == "list" or type(original) == list: + if self.code_format == "list" or type(original) is list: original = "\n".join(original) - if self.code_format == "list" or type(updated) == list: + if self.code_format == "list" or type(updated) is list: updated = "\n".join(updated) if original and not original.endswith("\n"): diff --git a/aider/coders/editblock_prompts.py b/aider/coders/editblock_prompts.py index 96b081bbd..da2acdf95 100644 --- a/aider/coders/editblock_prompts.py +++ b/aider/coders/editblock_prompts.py @@ -11,7 +11,7 @@ Respect and use existing conventions, libraries, etc that are already present in Take requests for changes to the supplied code. If the request is ambiguous, ask questions. -Always reply to the user in the same language they are using. +Always reply to the user in {language}. Once you understand the request you MUST: @@ -27,14 +27,18 @@ You can keep asking if you then decide you need to edit more files. All changes to files must use this *SEARCH/REPLACE block* format. ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*! +{shell_cmd_prompt} +""" + shell_cmd_prompt = """ 4. *Concisely* suggest any shell commands the user might want to run in ```bash blocks. Just suggest shell commands this way, not example code. +Only suggest complete shell commands that are ready to execute, without placeholders. +Only suggest at most a few shell commands at a time, not more than 1-3. Use the appropriate shell based on the user's system info: {platform} - Examples of when to suggest shell commands: - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content. @@ -45,6 +49,10 @@ Examples of when to suggest shell commands: - Etc. """ + no_shell_cmd_prompt = """ +Keep in mind these details about the user's platform and environment: +{platform} +""" example_messages = [ dict( role="user", @@ -137,7 +145,7 @@ from hello import hello system_reminder = """# *SEARCH/REPLACE block* Rules: Every *SEARCH/REPLACE block* must use this format: -1. The file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc. +1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc. 2. The opening fence and code language, eg: {fence[0]}python 3. The start of search block: <<<<<<< SEARCH 4. A contiguous chunk of lines to search for in the existing source code @@ -146,11 +154,14 @@ Every *SEARCH/REPLACE block* must use this format: 7. The end of the replace block: >>>>>>> REPLACE 8. The closing fence: {fence[1]} +Use the *FULL* file path, as shown to you by the user. + Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc. If the file contains code or other data wrapped/escaped in json/xml/quotes or other containers, you need to propose edits to the literal contents of the file, including the container markup. -*SEARCH/REPLACE* blocks will replace *all* matching occurrences. -Include enough lines to make the SEARCH blocks uniquely match the lines to change. +*SEARCH/REPLACE* blocks will *only* replace the first match occurrence. +Including multiple unique *SEARCH/REPLACE* blocks if needed. +Include enough lines in each SEARCH section to uniquely match each set of lines that need to change. Keep *SEARCH/REPLACE* blocks concise. Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file. @@ -161,16 +172,21 @@ Only create *SEARCH/REPLACE* blocks for files that the user has added to the cha To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location. +Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file. + If you want to put code in a new file, use a *SEARCH/REPLACE block* with: - A new file path, including dir name if needed - An empty `SEARCH` section - The new file's contents in the `REPLACE` section -To rename files which have been added to the chat, use shell commands. +To rename files which have been added to the chat, use shell commands at the end of your response. {lazy_prompt} ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*! +{shell_cmd_reminder} +""" + shell_cmd_reminder = """ Examples of when to suggest shell commands: - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content. diff --git a/aider/coders/editor_editblock_coder.py b/aider/coders/editor_editblock_coder.py new file mode 100644 index 000000000..301ab14af --- /dev/null +++ b/aider/coders/editor_editblock_coder.py @@ -0,0 +1,7 @@ +from .editblock_coder import EditBlockCoder +from .editor_editblock_prompts import EditorEditBlockPrompts + + +class EditorEditBlockCoder(EditBlockCoder): + edit_format = "editor-diff" + gpt_prompts = EditorEditBlockPrompts() diff --git a/aider/coders/editor_editblock_prompts.py b/aider/coders/editor_editblock_prompts.py new file mode 100644 index 000000000..595e28bee --- /dev/null +++ b/aider/coders/editor_editblock_prompts.py @@ -0,0 +1,16 @@ +# flake8: noqa: E501 + +from .editblock_prompts import EditBlockPrompts + + +class EditorEditBlockPrompts(EditBlockPrompts): + main_system = """Act as an expert software developer who edits source code. +{lazy_prompt} +Describe each change with a *SEARCH/REPLACE block* per the examples below. +All changes to files must use this *SEARCH/REPLACE block* format. +ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*! +""" + + shell_cmd_prompt = "" + no_shell_cmd_prompt = "" + shell_cmd_reminder = "" diff --git a/aider/coders/editor_whole_coder.py b/aider/coders/editor_whole_coder.py new file mode 100644 index 000000000..d3b4d278e --- /dev/null +++ b/aider/coders/editor_whole_coder.py @@ -0,0 +1,7 @@ +from .editor_whole_prompts import EditorWholeFilePrompts +from .wholefile_coder import WholeFileCoder + + +class EditorWholeFileCoder(WholeFileCoder): + edit_format = "editor-whole" + gpt_prompts = EditorWholeFilePrompts() diff --git a/aider/coders/editor_whole_prompts.py b/aider/coders/editor_whole_prompts.py new file mode 100644 index 000000000..7abd0ee53 --- /dev/null +++ b/aider/coders/editor_whole_prompts.py @@ -0,0 +1,10 @@ +# flake8: noqa: E501 + +from .wholefile_prompts import WholeFilePrompts + + +class EditorWholeFilePrompts(WholeFilePrompts): + main_system = """Act as an expert software developer and make changes to source code. +{lazy_prompt} +Output a copy of each file that needs changes. +""" diff --git a/aider/coders/search_replace.py b/aider/coders/search_replace.py index 0b83765ec..f89f629cb 100755 --- a/aider/coders/search_replace.py +++ b/aider/coders/search_replace.py @@ -484,7 +484,7 @@ def git_cherry_pick_osr_onto_o(texts): # cherry pick R onto original try: repo.git.cherry_pick(replace_hash, "--minimal") - except git.exc.GitCommandError: + except (git.exc.ODBError, git.exc.GitError): # merge conflicts! return @@ -522,7 +522,7 @@ def git_cherry_pick_sr_onto_so(texts): # cherry pick replace onto original try: repo.git.cherry_pick(replace_hash, "--minimal") - except git.exc.GitCommandError: + except (git.exc.ODBError, git.exc.GitError): # merge conflicts! return diff --git a/aider/coders/udiff_prompts.py b/aider/coders/udiff_prompts.py index 8084f885c..5e7ca2c13 100644 --- a/aider/coders/udiff_prompts.py +++ b/aider/coders/udiff_prompts.py @@ -12,7 +12,7 @@ Respect and use existing conventions, libraries, etc that are already present in Take requests for changes to the supplied code. If the request is ambiguous, ask questions. -Always reply to the user in the same language they are using. +Always reply to the user in {language}. For each file that needs to be changed, write out the changes similar to a unified diff like `diff -U0` would produce. """ diff --git a/aider/coders/wholefile_coder.py b/aider/coders/wholefile_coder.py index bfda70117..7cd9bac1b 100644 --- a/aider/coders/wholefile_coder.py +++ b/aider/coders/wholefile_coder.py @@ -58,6 +58,12 @@ class WholeFileCoder(Coder): fname = fname.strip("*") # handle **filename.py** fname = fname.rstrip(":") fname = fname.strip("`") + fname = fname.lstrip("#") + fname = fname.strip() + + # Issue #1232 + if len(fname) > 250: + fname = "" # Did gpt prepend a bogus dir? It especially likes to # include the path/to prefix from the one-shot example in @@ -123,15 +129,16 @@ class WholeFileCoder(Coder): def do_live_diff(self, full_path, new_lines, final): if Path(full_path).exists(): - orig_lines = self.io.read_text(full_path).splitlines(keepends=True) + orig_lines = self.io.read_text(full_path) + if orig_lines is not None: + orig_lines = orig_lines.splitlines(keepends=True) - show_diff = diffs.diff_partial_update( - orig_lines, - new_lines, - final=final, - ).splitlines() - output = show_diff - else: - output = ["```"] + new_lines + ["```"] + show_diff = diffs.diff_partial_update( + orig_lines, + new_lines, + final=final, + ).splitlines() + return show_diff + output = ["```"] + new_lines + ["```"] return output diff --git a/aider/coders/wholefile_prompts.py b/aider/coders/wholefile_prompts.py index 66eac016a..95a4bb87b 100644 --- a/aider/coders/wholefile_prompts.py +++ b/aider/coders/wholefile_prompts.py @@ -8,7 +8,7 @@ class WholeFilePrompts(CoderPrompts): Take requests for changes to the supplied code. If the request is ambiguous, ask questions. -Always reply to the user in the same language they are using. +Always reply to the user in {language}. {lazy_prompt} Once you understand the request you MUST: @@ -52,7 +52,7 @@ path/to/filename.js {fence[1]} Every *file listing* MUST use this format: -- First line: the filename with any originally provided path +- First line: the filename with any originally provided path; no extra markup, punctuation, comments, etc. **JUST** the filename with path. - Second line: opening {fence[0]} - ... entire content of the file ... - Final line: closing {fence[1]} diff --git a/aider/commands.py b/aider/commands.py index cf9a29d93..af74e281c 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -1,19 +1,25 @@ +import glob import os import re import subprocess import sys import tempfile from collections import OrderedDict +from os.path import expanduser from pathlib import Path -import git import pyperclip from PIL import Image, ImageGrab -from rich.text import Text +from prompt_toolkit.completion import Completion, PathCompleter +from prompt_toolkit.document import Document from aider import models, prompts, voice +from aider.editor import pipe_editor +from aider.format_settings import format_settings from aider.help import Help, install_help_extra from aider.llm import litellm +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 is_image_file @@ -29,9 +35,32 @@ class Commands: voice = None scraper = None - def __init__(self, io, coder, voice_language=None, verify_ssl=True): + def clone(self): + return Commands( + self.io, + None, + voice_language=self.voice_language, + verify_ssl=self.verify_ssl, + args=self.args, + parser=self.parser, + ) + + def __init__( + self, + io, + coder, + voice_language=None, + verify_ssl=True, + args=None, + parser=None, + verbose=False, + editor=None, + ): self.io = io self.coder = coder + self.parser = parser + self.args = args + self.verbose = verbose self.verify_ssl = verify_ssl if voice_language == "auto": @@ -40,6 +69,7 @@ class Commands: self.voice_language = voice_language self.help = None + self.editor = editor def cmd_model(self, args): "Switch to a new LLM" @@ -119,8 +149,8 @@ class Commands: else: self.io.tool_output("Please provide a partial model name to search for.") - def cmd_web(self, args, paginate=True): - "Scrape a webpage, convert to markdown and add to the chat" + def cmd_web(self, args, return_content=False): + "Scrape a webpage, convert to markdown and send in a message" url = args.strip() if not url: @@ -131,30 +161,40 @@ class Commands: if not self.scraper: res = install_playwright(self.io) if not res: - self.io.tool_error("Unable to initialize playwright.") + self.io.tool_warning("Unable to initialize playwright.") self.scraper = Scraper( print_error=self.io.tool_error, playwright_available=res, verify_ssl=self.verify_ssl ) content = self.scraper.scrape(url) or "" - content = f"{url}:\n\n" + content + content = f"Here is the content of {url}:\n\n" + content + if return_content: + return content - self.io.tool_output("... done.") + self.io.tool_output("... added to chat.") - if paginate: - with self.io.console.pager(): - self.io.console.print(Text(content)) - - return content + self.coder.cur_messages += [ + dict(role="user", content=content), + dict(role="assistant", content="Ok."), + ] def is_command(self, inp): return inp[0] in "/!" + def get_raw_completions(self, cmd): + assert cmd.startswith("/") + cmd = cmd[1:] + cmd = cmd.replace("-", "_") + + raw_completer = getattr(self, f"completions_raw_{cmd}", None) + return raw_completer + def get_completions(self, cmd): assert cmd.startswith("/") cmd = cmd[1:] + cmd = cmd.replace("-", "_") fun = getattr(self, f"completions_{cmd}", None) if not fun: return @@ -175,10 +215,14 @@ class Commands: cmd_name = cmd_name.replace("-", "_") cmd_method_name = f"cmd_{cmd_name}" cmd_method = getattr(self, cmd_method_name, None) - if cmd_method: - return cmd_method(args) - else: + if not cmd_method: self.io.tool_output(f"Error: Command {cmd_name} not found.") + return + + try: + return cmd_method(args) + except ANY_GIT_ERROR as err: + self.io.tool_error(f"Unable to complete {cmd_name}: {err}") def matching_commands(self, inp): words = inp.strip().split() @@ -186,7 +230,7 @@ class Commands: return first_word = words[0] - rest_inp = inp[len(words[0]) :] + rest_inp = inp[len(words[0]) :].strip() all_commands = self.get_commands() matching_commands = [cmd for cmd in all_commands if cmd.startswith(first_word)] @@ -194,6 +238,7 @@ class Commands: def run(self, inp): if inp.startswith("!"): + self.coder.event("command_run") return self.do_run("run", inp[1:]) res = self.matching_commands(inp) @@ -201,9 +246,13 @@ class Commands: return matching_commands, first_word, rest_inp = res if len(matching_commands) == 1: - return self.do_run(matching_commands[0][1:], rest_inp) + command = matching_commands[0][1:] + self.coder.event(f"command_{command}") + return self.do_run(command, rest_inp) elif first_word in matching_commands: - return self.do_run(first_word[1:], rest_inp) + command = first_word[1:] + self.coder.event(f"command_{command}") + return self.do_run(command, rest_inp) elif len(matching_commands) > 1: self.io.tool_error(f"Ambiguous command: {', '.join(matching_commands)}") else: @@ -214,20 +263,25 @@ class Commands: def cmd_commit(self, args=None): "Commit edits to the repo made outside the chat (commit message optional)" + try: + self.raw_cmd_commit(args) + except ANY_GIT_ERROR as err: + self.io.tool_error(f"Unable to complete commit: {err}") + def raw_cmd_commit(self, args=None): if not self.coder.repo: self.io.tool_error("No git repository found.") return if not self.coder.repo.is_dirty(): - self.io.tool_error("No more changes to commit.") + self.io.tool_warning("No more changes to commit.") return commit_message = args.strip() if args else None self.coder.repo.commit(message=commit_message) def cmd_lint(self, args="", fnames=None): - "Lint and fix provided files or in-chat files if none provided" + "Lint and fix in-chat files or all dirty files if none in chat" if not self.coder.repo: self.io.tool_error("No git repository found.") @@ -241,7 +295,7 @@ class Commands: fnames = self.coder.repo.get_dirty_files() if not fnames: - self.io.tool_error("No dirty files to lint.") + self.io.tool_warning("No dirty files to lint.") return fnames = [self.coder.abs_root_path(fname) for fname in fnames] @@ -252,18 +306,18 @@ class Commands: errors = self.coder.linter.lint(fname) except FileNotFoundError as err: self.io.tool_error(f"Unable to lint {fname}") - self.io.tool_error(str(err)) + self.io.tool_output(str(err)) continue if not errors: continue - self.io.tool_error(errors) + self.io.tool_output(errors) if not self.io.confirm_ask(f"Fix lint errors in {fname}?", default="y"): continue # Commit everything before we start fixing lint errors - if self.coder.repo.is_dirty(): + if self.coder.repo.is_dirty() and self.coder.dirty_commits: self.cmd_commit("") if not lint_coder: @@ -278,7 +332,7 @@ class Commands: lint_coder.run(errors) lint_coder.abs_fnames = set() - if lint_coder and self.coder.repo.is_dirty(): + if lint_coder and self.coder.repo.is_dirty() and self.coder.auto_commits: self.cmd_commit("") def cmd_clear(self, args): @@ -406,15 +460,37 @@ class Commands: def cmd_undo(self, args): "Undo the last git commit if it was done by aider" + try: + self.raw_cmd_undo(args) + except ANY_GIT_ERROR as err: + self.io.tool_error(f"Unable to complete undo: {err}") + + def raw_cmd_undo(self, args): if not self.coder.repo: self.io.tool_error("No git repository found.") return - last_commit = self.coder.repo.repo.head.commit - if not last_commit.parents: + last_commit = self.coder.repo.get_head_commit() + if not last_commit or not last_commit.parents: self.io.tool_error("This is the first commit in the repository. Cannot undo.") return + last_commit_hash = self.coder.repo.get_head_commit_sha(short=True) + last_commit_message = self.coder.repo.get_head_commit_message("(unknown)").strip() + if last_commit_hash not in self.coder.aider_commit_hashes: + self.io.tool_error("The last commit was not made by aider in this chat session.") + self.io.tool_output( + "You could try `/git reset --hard HEAD^` but be aware that this is a destructive" + " command!" + ) + return + + if len(last_commit.parents) > 1: + self.io.tool_error( + f"The last commit {last_commit.hexsha} has more than 1 parent, can't undo." + ) + return + prev_commit = last_commit.parents[0] changed_files_last_commit = [item.a_path for item in last_commit.diff(prev_commit)] @@ -440,7 +516,7 @@ class Commands: try: remote_head = self.coder.repo.repo.git.rev_parse(f"origin/{current_branch}") has_origin = True - except git.exc.GitCommandError: + except ANY_GIT_ERROR: has_origin = False if has_origin: @@ -451,19 +527,25 @@ class Commands: ) return - last_commit_hash = self.coder.repo.repo.head.commit.hexsha[:7] - last_commit_message = self.coder.repo.repo.head.commit.message.strip() - if last_commit_hash not in self.coder.aider_commit_hashes: - self.io.tool_error("The last commit was not made by aider in this chat session.") - self.io.tool_error( - "You could try `/git reset --hard HEAD^` but be aware that this is a destructive" - " command!" - ) - return - # Reset only the files which are part of `last_commit` + restored = set() + unrestored = set() for file_path in changed_files_last_commit: - self.coder.repo.repo.git.checkout("HEAD~1", file_path) + try: + self.coder.repo.repo.git.checkout("HEAD~1", file_path) + restored.add(file_path) + except ANY_GIT_ERROR: + unrestored.add(file_path) + + if unrestored: + self.io.tool_error(f"Error restoring {file_path}, aborting undo.") + self.io.tool_output("Restored files:") + for file in restored: + self.io.tool_output(f" {file}") + self.io.tool_output("Unable to restore files:") + for file in unrestored: + self.io.tool_output(f" {file}") + return # Move the HEAD back before the latest commit self.coder.repo.repo.git.reset("--soft", "HEAD~1") @@ -471,8 +553,8 @@ class Commands: self.io.tool_output(f"Removed: {last_commit_hash} {last_commit_message}") # Get the current HEAD after undo - current_head_hash = self.coder.repo.repo.head.commit.hexsha[:7] - current_head_message = self.coder.repo.repo.head.commit.message.strip() + current_head_hash = self.coder.repo.get_head_commit_sha(short=True) + current_head_message = self.coder.repo.get_head_commit_message("(unknown)").strip() self.io.tool_output(f"Now at: {current_head_hash} {current_head_message}") if self.coder.main_model.send_undo_reply: @@ -480,11 +562,17 @@ class Commands: def cmd_diff(self, args=""): "Display the diff of changes since the last message" + try: + self.raw_cmd_diff(args) + except ANY_GIT_ERROR as err: + self.io.tool_error(f"Unable to complete diff: {err}") + + def raw_cmd_diff(self, args=""): if not self.coder.repo: self.io.tool_error("No git repository found.") return - current_head = self.coder.repo.get_head() + current_head = self.coder.repo.get_head_commit_sha() if current_head is None: self.io.tool_error("Unable to get current commit. The repository might be empty.") return @@ -495,7 +583,7 @@ class Commands: commit_before_message = self.coder.commit_before_message[-2] if not commit_before_message or commit_before_message == current_head: - self.io.tool_error("No changes to display since the last message.") + self.io.tool_warning("No changes to display since the last message.") return self.io.tool_output(f"Diff since {commit_before_message[:7]}...") @@ -506,16 +594,69 @@ class Commands: "HEAD", ) - # don't use io.tool_output() because we don't want to log or further colorize - print(diff) + self.io.print(diff) def quote_fname(self, fname): if " " in fname and '"' not in fname: fname = f'"{fname}"' return fname - def completions_read(self): - return self.completions_add() + def completions_raw_read_only(self, document, complete_event): + # Get the text before the cursor + text = document.text_before_cursor + + # Skip the first word and the space after it + after_command = text.split()[-1] + + # Create a new Document object with the text after the command + new_document = Document(after_command, cursor_position=len(after_command)) + + def get_paths(): + return [self.coder.root] if self.coder.root else None + + path_completer = PathCompleter( + get_paths=get_paths, + only_directories=False, + expanduser=True, + ) + + # Adjust the start_position to replace all of 'after_command' + adjusted_start_position = -len(after_command) + + # Collect all completions + all_completions = [] + + # Iterate over the completions and modify them + for completion in path_completer.get_completions(new_document, complete_event): + quoted_text = self.quote_fname(after_command + completion.text) + all_completions.append( + Completion( + text=quoted_text, + start_position=adjusted_start_position, + display=completion.display, + style=completion.style, + selected_style=completion.selected_style, + ) + ) + + # Add completions from the 'add' command + add_completions = self.completions_add() + for completion in add_completions: + if after_command in completion: + all_completions.append( + Completion( + text=completion, + start_position=adjusted_start_position, + display=completion, + ) + ) + + # Sort all completions based on their text + sorted_completions = sorted(all_completions, key=lambda c: c.text) + + # Yield the sorted completions + for completion in sorted_completions: + yield completion def completions_add(self): files = set(self.coder.get_all_relative_files()) @@ -524,12 +665,17 @@ class Commands: return files def glob_filtered_to_repo(self, pattern): + if not pattern.strip(): + return [] try: if os.path.isabs(pattern): # Handle absolute paths raw_matched_files = [Path(pattern)] else: - raw_matched_files = list(Path(self.coder.root).glob(pattern)) + try: + raw_matched_files = list(Path(self.coder.root).glob(pattern)) + except (IndexError, AttributeError): + raw_matched_files = [] except ValueError as err: self.io.tool_error(f"Error matching {pattern}: {err}") raw_matched_files = [] @@ -539,9 +685,9 @@ class Commands: matched_files += expand_subdir(fn) matched_files = [ - str(Path(fn).relative_to(self.coder.root)) + fn.relative_to(self.coder.root) for fn in matched_files - if Path(fn).is_relative_to(self.coder.root) + if fn.is_relative_to(self.coder.root) ] # if repo, filter against it @@ -553,9 +699,7 @@ class Commands: return res def cmd_add(self, args): - "Add files to the chat so GPT can edit them or review them in detail" - - added_fnames = [] + "Add files to the chat so aider can edit them or review them in detail" all_matched_files = set() @@ -567,7 +711,7 @@ class Commands: fname = Path(self.coder.root) / word if self.coder.repo and self.coder.repo.ignored_file(fname): - self.io.tool_error(f"Skipping {fname} due to aiderignore or --subtree-only.") + self.io.tool_warning(f"Skipping {fname} due to aiderignore or --subtree-only.") continue if fname.exists(): @@ -582,17 +726,25 @@ class Commands: all_matched_files.update(matched_files) continue - if self.io.confirm_ask(f"No files matched '{word}'. Do you want to create {fname}?"): - if "*" in str(fname) or "?" in str(fname): - self.io.tool_error(f"Cannot create file with wildcard characters: {fname}") - else: - try: - fname.touch() - all_matched_files.add(str(fname)) - except OSError as e: - self.io.tool_error(f"Error creating file {fname}: {e}") + if "*" in str(fname) or "?" in str(fname): + self.io.tool_error( + f"No match, and cannot create file with wildcard characters: {fname}" + ) + continue - for matched_file in all_matched_files: + if fname.exists() and fname.is_dir() and self.coder.repo: + self.io.tool_error(f"Directory {fname} is not in git.") + self.io.tool_output(f"You can add to git with: /git add {fname}") + continue + + if self.io.confirm_ask(f"No files matched '{word}'. Do you want to create {fname}?"): + try: + fname.touch() + all_matched_files.add(str(fname)) + except OSError as e: + self.io.tool_error(f"Error creating file {fname}: {e}") + + for matched_file in sorted(all_matched_files): abs_file_path = self.coder.abs_root_path(matched_file) if not abs_file_path.startswith(self.coder.root) and not is_image_file(matched_file): @@ -601,8 +753,13 @@ class Commands: ) continue + if self.coder.repo and self.coder.repo.git_ignored_file(matched_file): + self.io.tool_error(f"Can't add {matched_file} which is in gitignore") + continue + if abs_file_path in self.coder.abs_fnames: - self.io.tool_error(f"{matched_file} is already in the chat") + self.io.tool_error(f"{matched_file} is already in the chat as an editable file") + continue elif abs_file_path in self.coder.abs_read_only_fnames: if self.coder.repo and self.coder.repo.path_in_repo(matched_file): self.coder.abs_read_only_fnames.remove(abs_file_path) @@ -610,17 +767,17 @@ class Commands: self.io.tool_output( f"Moved {matched_file} from read-only to editable files in the chat" ) - added_fnames.append(matched_file) else: self.io.tool_error( f"Cannot add {matched_file} as it's not part of the repository" ) else: - if is_image_file(matched_file) and not self.coder.main_model.accepts_images: + if is_image_file(matched_file) and not self.coder.main_model.info.get( + "supports_vision" + ): self.io.tool_error( f"Cannot add image file {matched_file} as the" - f" {self.coder.main_model.name} does not support image.\nYou can run `aider" - " --4-turbo-vision` to use GPT-4 Turbo with Vision." + f" {self.coder.main_model.name} does not support images." ) continue content = self.io.read_text(abs_file_path) @@ -630,7 +787,6 @@ class Commands: self.coder.abs_fnames.add(abs_file_path) self.io.tool_output(f"Added {matched_file} to the chat") self.coder.check_added_files() - added_fnames.append(matched_file) def completions_drop(self): files = self.coder.get_inchat_relative_files() @@ -672,7 +828,7 @@ class Commands: self.io.tool_output(f"Removed {matched_file} from the chat") def cmd_git(self, args): - "Run a git command" + "Run a git command (output excluded from chat)" combined_output = None try: args = "git " + args @@ -702,67 +858,49 @@ class Commands: if not args and self.coder.test_cmd: args = self.coder.test_cmd + if not args: + return + if not callable(args): + if type(args) is not str: + raise ValueError(repr(args)) return self.cmd_run(args, True) errors = args() if not errors: return - self.io.tool_error(errors, strip=False) + self.io.tool_output(errors) return errors def cmd_run(self, args, add_on_nonzero_exit=False): "Run a shell command and optionally add the output to the chat (alias: !)" - combined_output = None - instructions = None - try: - result = subprocess.run( - args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - shell=True, - encoding=self.io.encoding, - errors="replace", - ) - combined_output = result.stdout - except Exception as e: - self.io.tool_error(f"Error running command: {e}") + exit_status, combined_output = run_cmd( + args, verbose=self.verbose, error_print=self.io.tool_error, cwd=self.coder.root + ) if combined_output is None: return - self.io.tool_output(combined_output) - if add_on_nonzero_exit: - add = result.returncode != 0 + add = exit_status != 0 else: - response = self.io.prompt_ask( - "Add the output to the chat?\n[Y/n/instructions]", - ).strip() - - if response.lower() in ["yes", "y"]: - add = True - elif response.lower() in ["no", "n"]: - add = False - else: - add = True - instructions = response + add = self.io.confirm_ask("Add command output to the chat?") if add: - for line in combined_output.splitlines(): - self.io.tool_output(line, log_only=True) + num_lines = len(combined_output.strip().splitlines()) + line_plural = "line" if num_lines == 1 else "lines" + self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.") msg = prompts.run_output.format( command=args, output=combined_output, ) - if instructions: - msg = instructions + "\n\n" + msg - - return msg + self.coder.cur_messages += [ + dict(role="user", content=msg), + dict(role="assistant", content="Ok."), + ] def cmd_exit(self, args): "Exit the application" @@ -834,6 +972,7 @@ class Commands: self.basic_help() return + self.coder.event("interactive help") from aider.coders import Coder if not self.help: @@ -877,14 +1016,6 @@ class Commands: show_announcements=False, ) - def clone(self): - return Commands( - self.io, - None, - voice_language=self.voice_language, - verify_ssl=self.verify_ssl, - ) - def cmd_ask(self, args): "Ask questions about the code base without editing any files" return self._generic_chat_command(args, "ask") @@ -893,6 +1024,10 @@ class Commands: "Ask for changes to your code" 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" + 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.") @@ -945,7 +1080,7 @@ class Commands: self.io.tool_error("To use /voice you must provide an OpenAI API key.") return try: - self.voice = voice.Voice() + self.voice = voice.Voice(audio_format=self.args.voice_format) except voice.SoundDeviceError: self.io.tool_error( "Unable to import `sounddevice` and/or `soundfile`, is portaudio installed?" @@ -977,14 +1112,15 @@ class Commands: if text: self.io.add_to_input_history(text) - print() + self.io.print() self.io.user_input(text, log_only=False) - print() + self.io.print() return text - def cmd_clipboard(self, args): - "Add image/text from the clipboard to the chat (optionally provide a name for the image)" + def cmd_paste(self, args): + """Paste image/text from the clipboard into the chat.\ + Optionally provide a name for the image.""" try: # Check for image first image = ImageGrab.grabclipboard() @@ -1035,33 +1171,76 @@ class Commands: def cmd_read_only(self, args): "Add files to the chat that are for reference, not to be edited" if not args.strip(): - self.io.tool_error("Please provide filenames to read.") + self.io.tool_error("Please provide filenames or directories to read.") return filenames = parse_quoted_filenames(args) - for word in filenames: - # Expand the home directory if the path starts with "~" - expanded_path = os.path.expanduser(word) - abs_path = self.coder.abs_root_path(expanded_path) + all_paths = [] - if not os.path.exists(abs_path): - self.io.tool_error(f"File not found: {abs_path}") - continue + # First collect all expanded paths + for pattern in filenames: + expanded_pattern = expanduser(pattern) + if os.path.isabs(expanded_pattern): + # For absolute paths, glob it + matches = list(glob.glob(expanded_pattern)) + else: + # For relative paths and globs, use glob from the root directory + matches = list(Path(self.coder.root).glob(expanded_pattern)) - if not os.path.isfile(abs_path): - self.io.tool_error(f"Not a file: {abs_path}") - continue + if not matches: + self.io.tool_error(f"No matches found for: {pattern}") + else: + all_paths.extend(matches) - if abs_path in self.coder.abs_fnames: - self.io.tool_error(f"{word} is already in the chat as an editable file") - continue + # Then process them in sorted order + for path in sorted(all_paths): + abs_path = self.coder.abs_root_path(path) + if os.path.isfile(abs_path): + self._add_read_only_file(abs_path, path) + elif os.path.isdir(abs_path): + self._add_read_only_directory(abs_path, path) + else: + self.io.tool_error(f"Not a file or directory: {abs_path}") - if abs_path in self.coder.abs_read_only_fnames: - self.io.tool_error(f"{word} is already in the chat as a read-only file") - continue + def _add_read_only_file(self, abs_path, original_name): + if is_image_file(original_name) and not self.coder.main_model.info.get("supports_vision"): + self.io.tool_error( + f"Cannot add image file {original_name} as the" + f" {self.coder.main_model.name} does not support images." + ) + return + if abs_path in self.coder.abs_read_only_fnames: + self.io.tool_error(f"{original_name} is already in the chat as a read-only file") + return + elif abs_path in self.coder.abs_fnames: + self.coder.abs_fnames.remove(abs_path) self.coder.abs_read_only_fnames.add(abs_path) - self.io.tool_output(f"Added {word} to read-only files.") + self.io.tool_output( + f"Moved {original_name} from editable to read-only files in the chat" + ) + else: + self.coder.abs_read_only_fnames.add(abs_path) + self.io.tool_output(f"Added {original_name} to read-only files.") + + def _add_read_only_directory(self, abs_path, original_name): + added_files = 0 + for root, _, files in os.walk(abs_path): + for file in files: + file_path = os.path.join(root, file) + if ( + file_path not in self.coder.abs_fnames + and file_path not in self.coder.abs_read_only_fnames + ): + self.coder.abs_read_only_fnames.add(file_path) + added_files += 1 + + if added_files > 0: + self.io.tool_output( + f"Added {added_files} files from directory {original_name} to read-only files." + ) + else: + self.io.tool_output(f"No new files added from directory {original_name}.") def cmd_map(self, args): "Print out the current repository map" @@ -1077,9 +1256,120 @@ class Commands: if repo_map: self.io.tool_output("The repo map has been refreshed, use /map to view it.") + def cmd_settings(self, args): + "Print out the current settings" + settings = format_settings(self.parser, self.args) + announcements = "\n".join(self.coder.get_announcements()) + output = f"{announcements}\n{settings}" + self.io.tool_output(output) + + def completions_raw_load(self, document, complete_event): + return self.completions_raw_read_only(document, complete_event) + + def cmd_load(self, args): + "Load and execute commands from a file" + if not args.strip(): + self.io.tool_error("Please provide a filename containing commands to load.") + return + + try: + with open(args.strip(), "r", encoding=self.io.encoding, errors="replace") as f: + commands = f.readlines() + except FileNotFoundError: + self.io.tool_error(f"File not found: {args}") + return + except Exception as e: + self.io.tool_error(f"Error reading file: {e}") + return + + for cmd in commands: + cmd = cmd.strip() + if not cmd or cmd.startswith("#"): + continue + + self.io.tool_output(f"\nExecuting: {cmd}") + self.run(cmd) + + def completions_raw_save(self, document, complete_event): + return self.completions_raw_read_only(document, complete_event) + + def cmd_save(self, args): + "Save commands to a file that can reconstruct the current chat session's files" + if not args.strip(): + self.io.tool_error("Please provide a filename to save the commands to.") + return + + try: + with open(args.strip(), "w", encoding=self.io.encoding) as f: + f.write("/drop\n") + # Write commands to add editable files + for fname in sorted(self.coder.abs_fnames): + rel_fname = self.coder.get_rel_fname(fname) + f.write(f"/add {rel_fname}\n") + + # Write commands to add read-only files + for fname in sorted(self.coder.abs_read_only_fnames): + # Use absolute path for files outside repo root, relative path for files inside + if Path(fname).is_relative_to(self.coder.root): + rel_fname = self.coder.get_rel_fname(fname) + f.write(f"/read-only {rel_fname}\n") + else: + f.write(f"/read-only {fname}\n") + + self.io.tool_output(f"Saved commands to {args.strip()}") + except Exception as e: + self.io.tool_error(f"Error saving commands to file: {e}") + + def cmd_copy(self, args): + "Copy the last assistant message to the clipboard" + all_messages = self.coder.done_messages + self.coder.cur_messages + assistant_messages = [msg for msg in reversed(all_messages) if msg["role"] == "assistant"] + + if not assistant_messages: + self.io.tool_error("No assistant messages found to copy.") + return + + last_assistant_message = assistant_messages[0]["content"] + + try: + pyperclip.copy(last_assistant_message) + preview = ( + last_assistant_message[:50] + "..." + if len(last_assistant_message) > 50 + else last_assistant_message + ) + self.io.tool_output(f"Copied last assistant message to clipboard. Preview: {preview}") + except pyperclip.PyperclipException as e: + self.io.tool_error(f"Failed to copy to clipboard: {str(e)}") + self.io.tool_output( + "You may need to install xclip or xsel on Linux, or pbcopy on macOS." + ) + except Exception as e: + self.io.tool_error(f"An unexpected error occurred while copying to clipboard: {str(e)}") + + def cmd_report(self, args): + "Report a problem by opening a GitHub Issue" + from aider.report import report_github_issue + + announcements = "\n".join(self.coder.get_announcements()) + issue_text = announcements + + if args.strip(): + title = args.strip() + else: + title = None + + report_github_issue(issue_text, title=title, confirm=False) + + def cmd_editor(self, initial_content=""): + "Open an editor to write a prompt" + + user_input = pipe_editor(initial_content, suffix="md", editor=self.editor) + if user_input.strip(): + self.io.set_placeholder(user_input.rstrip()) + def expand_subdir(file_path): - file_path = Path(file_path) if file_path.is_file(): yield file_path return @@ -1087,7 +1377,7 @@ def expand_subdir(file_path): if file_path.is_dir(): for file in file_path.rglob("*"): if file.is_file(): - yield str(file) + yield file def parse_quoted_filenames(args): @@ -1097,11 +1387,7 @@ def parse_quoted_filenames(args): def get_help_md(): - from aider.coders import Coder - from aider.models import Model - - coder = Coder(Model("gpt-3.5-turbo"), None) - md = coder.commands.get_help_md() + md = Commands(None, None).get_help_md() return md diff --git a/aider/diffs.py b/aider/diffs.py index 784745688..46266ac67 100644 --- a/aider/diffs.py +++ b/aider/diffs.py @@ -50,7 +50,6 @@ def diff_partial_update(lines_orig, lines_updated, final=False, fname=None): # dump(lines_orig) # dump(lines_updated) - assert_newlines(lines_orig) assert_newlines(lines_orig) num_orig_lines = len(lines_orig) diff --git a/aider/editor.py b/aider/editor.py new file mode 100644 index 000000000..14473e5d2 --- /dev/null +++ b/aider/editor.py @@ -0,0 +1,146 @@ +""" +Editor module for handling system text editor interactions. + +This module provides functionality to: +- Discover and launch the system's configured text editor +- Create and manage temporary files for editing +- Handle editor preferences from environment variables +- Support cross-platform editor operations +""" + +import os +import platform +import shlex +import subprocess +import tempfile + +from rich.console import Console + +DEFAULT_EDITOR_NIX = "vi" +DEFAULT_EDITOR_OS_X = "vim" +DEFAULT_EDITOR_WINDOWS = "notepad" + +console = Console() + + +def print_status_message(success, message, style=None): + """ + Print a status message with appropriate styling. + + :param success: Whether the operation was successful + :param message: The message to display + :param style: Optional style override. If None, uses green for success and red for failure + """ + if style is None: + style = "bold green" if success else "bold red" + console.print(message, style=style) + print("") + + +def write_temp_file( + input_data="", + suffix=None, + prefix=None, + dir=None, +): + """ + Create a temporary file with the given input data. + + :param input_data: Content to write to the temporary file + :param suffix: Optional file extension (without the dot) + :param prefix: Optional prefix for the temporary filename + :param dir: Optional directory to create the file in + :return: Path to the created temporary file + :raises: OSError if file creation or writing fails + """ + kwargs = {"prefix": prefix, "dir": dir} + if suffix: + kwargs["suffix"] = f".{suffix}" + fd, filepath = tempfile.mkstemp(**kwargs) + try: + with os.fdopen(fd, "w") as f: + f.write(input_data) + except Exception: + os.close(fd) + raise + return filepath + + +def get_environment_editor(default=None): + """ + Fetches the preferred editor from the environment variables. + + This function checks the following environment variables in order to + determine the user's preferred editor: + + - VISUAL + - EDITOR + + :param default: The default editor to return if no environment variable is set. + :type default: str or None + :return: The preferred editor as specified by environment variables or the default value. + :rtype: str or None + """ + editor = os.environ.get("VISUAL", os.environ.get("EDITOR", default)) + return editor + + +def discover_editor(editor_override=None): + """ + Discovers and returns the appropriate editor command as a list of arguments. + + Handles cases where the editor command includes arguments, including quoted arguments + with spaces (e.g. 'vim -c "set noswapfile"'). + + :return: A list of command parts ready for subprocess execution + :rtype: list[str] + """ + system = platform.system() + if system == "Windows": + default_editor = DEFAULT_EDITOR_WINDOWS + elif system == "Darwin": + default_editor = DEFAULT_EDITOR_OS_X + else: + default_editor = DEFAULT_EDITOR_NIX + if editor_override: + editor = editor_override + else: + editor = get_environment_editor(default_editor) + try: + return shlex.split(editor) + except ValueError as e: + raise RuntimeError(f"Invalid editor command format '{editor}': {e}") + + +def pipe_editor(input_data="", suffix=None, editor=None): + """ + Opens the system editor with optional input data and returns the edited content. + + This function creates a temporary file with the provided input data, opens it in + the system editor, waits for the user to make changes and close the editor, then + reads and returns the modified content. The temporary file is deleted afterwards. + + :param input_data: Initial content to populate the editor with + :type input_data: str + :param suffix: Optional file extension for the temporary file (e.g. '.txt', '.md') + :type suffix: str or None + :return: The edited content after the editor is closed + :rtype: str + """ + filepath = write_temp_file(input_data, suffix) + command_parts = discover_editor(editor) + command_parts.append(filepath) + subprocess.call(command_parts) + with open(filepath, "r") as f: + output_data = f.read() + try: + os.remove(filepath) + except PermissionError: + print_status_message( + False, + ( + f"WARNING: Unable to delete temporary file {filepath!r}. You may need to delete it" + " manually." + ), + ) + return output_data diff --git a/aider/exceptions.py b/aider/exceptions.py new file mode 100644 index 000000000..e8fcc5997 --- /dev/null +++ b/aider/exceptions.py @@ -0,0 +1,81 @@ +from dataclasses import dataclass + + +@dataclass +class ExInfo: + name: str + retry: bool + description: str + + +EXCEPTIONS = [ + ExInfo("APIConnectionError", True, None), + ExInfo("APIError", True, None), + ExInfo("APIResponseValidationError", True, None), + ExInfo( + "AuthenticationError", + False, + "The API provider is not able to authenticate you. Check your API key.", + ), + ExInfo("AzureOpenAIError", True, None), + ExInfo("BadRequestError", False, None), + ExInfo("BudgetExceededError", True, None), + ExInfo( + "ContentPolicyViolationError", + True, + "The API provider has refused the request due to a safety policy about the content.", + ), + ExInfo("ContextWindowExceededError", False, None), # special case handled in base_coder + ExInfo("InternalServerError", True, "The API provider's servers are down or overloaded."), + ExInfo("InvalidRequestError", True, None), + ExInfo("JSONSchemaValidationError", True, None), + ExInfo("NotFoundError", False, None), + ExInfo("OpenAIError", True, None), + ExInfo( + "RateLimitError", + True, + "The API provider has rate limited you. Try again later or check your quotas.", + ), + ExInfo("RouterRateLimitError", True, None), + ExInfo("ServiceUnavailableError", True, "The API provider's servers are down or overloaded."), + ExInfo("UnprocessableEntityError", True, None), + ExInfo("UnsupportedParamsError", True, None), + ExInfo( + "Timeout", + True, + "The API provider timed out without returning a response. They may be down or overloaded.", + ), +] + + +class LiteLLMExceptions: + exceptions = dict() + + def __init__(self): + self._load() + + def _load(self, strict=False): + import litellm + + for var in dir(litellm): + if not var.endswith("Error"): + continue + + ex_info = None + for exi in EXCEPTIONS: + if var == exi.name: + ex_info = exi + break + + if strict and not ex_info: + raise ValueError(f"{var} is in litellm but not in aider's exceptions list") + + ex = getattr(litellm, var) + self.exceptions[ex] = ex_info + + def exceptions_tuple(self): + return tuple(self.exceptions) + + def get_ex_info(self, ex): + """Return the ExInfo for a given exception instance""" + return self.exceptions.get(ex.__class__, ExInfo(None, None, None)) diff --git a/aider/format_settings.py b/aider/format_settings.py new file mode 100644 index 000000000..0ad54aa51 --- /dev/null +++ b/aider/format_settings.py @@ -0,0 +1,26 @@ +def scrub_sensitive_info(args, text): + # Replace sensitive information with last 4 characters + if text and args.openai_api_key: + last_4 = args.openai_api_key[-4:] + text = text.replace(args.openai_api_key, f"...{last_4}") + if text and args.anthropic_api_key: + last_4 = args.anthropic_api_key[-4:] + text = text.replace(args.anthropic_api_key, f"...{last_4}") + return text + + +def format_settings(parser, args): + show = scrub_sensitive_info(args, parser.format_values()) + # clean up the headings for consistency w/ new lines + heading_env = "Environment Variables:" + heading_defaults = "Defaults:" + if heading_env in show: + show = show.replace(heading_env, "\n" + heading_env) + show = show.replace(heading_defaults, "\n" + heading_defaults) + show += "\n" + show += "Option settings:\n" + for arg, val in sorted(vars(args).items()): + if val: + val = scrub_sensitive_info(args, str(val)) + show += f" - {arg}: {val}\n" # noqa: E221 + return show diff --git a/aider/gui.py b/aider/gui.py index f34e66376..7fa90bc38 100755 --- a/aider/gui.py +++ b/aider/gui.py @@ -26,6 +26,10 @@ class CaptureIO(InputOutput): self.lines.append(msg) super().tool_error(msg) + def tool_warning(self, msg): + self.lines.append(msg) + super().tool_warning(msg) + def get_captured_lines(self): lines = self.lines self.lines = [] @@ -156,7 +160,7 @@ class GUI: st.warning( "This browser version of aider is experimental. Please share feedback in [GitHub" - " issues](https://github.com/paul-gauthier/aider/issues)." + " issues](https://github.com/Aider-AI/aider/issues)." ) def do_settings_tab(self): @@ -524,7 +528,7 @@ def gui_main(): page_icon=urls.favicon, menu_items={ "Get Help": urls.website, - "Report a bug": "https://github.com/paul-gauthier/aider/issues", + "Report a bug": "https://github.com/Aider-AI/aider/issues", "About": "# Aider\nAI pair programming in your browser.", }, ) diff --git a/aider/help.py b/aider/help.py index c7c8f7f48..c76188d12 100755 --- a/aider/help.py +++ b/aider/help.py @@ -1,6 +1,8 @@ #!/usr/bin/env python +import json import os +import shutil import warnings from pathlib import Path @@ -38,24 +40,45 @@ def get_package_files(): def fname_to_url(filepath): - website = "website/" - index = "/index.md" + website = "website" + index = "index.md" md = ".md" - docid = "" - if filepath.startswith("website/_includes/"): - pass - elif filepath.startswith(website): - docid = filepath[len(website) :] + # Convert backslashes to forward slashes for consistency + filepath = filepath.replace("\\", "/") - if filepath.endswith(index): - filepath = filepath[: -len(index)] + "/" - elif filepath.endswith(md): - filepath = filepath[: -len(md)] + ".html" + # Convert to Path object for easier manipulation + path = Path(filepath) - docid = "https://aider.chat/" + filepath + # Split the path into parts + parts = path.parts - return docid + # Find the 'website' part in the path + try: + website_index = [p.lower() for p in parts].index(website.lower()) + except ValueError: + return "" # 'website' not found in the path + + # Extract the part of the path starting from 'website' + relevant_parts = parts[website_index + 1 :] + + # Handle _includes directory + if relevant_parts and relevant_parts[0].lower() == "_includes": + return "" + + # Join the remaining parts + url_path = "/".join(relevant_parts) + + # Handle index.md and other .md files + if url_path.lower().endswith(index.lower()): + url_path = url_path[: -len(index)] + elif url_path.lower().endswith(md.lower()): + url_path = url_path[: -len(md)] + ".html" + + # Ensure the URL starts and ends with '/' + url_path = url_path.strip("/") + + return f"https://aider.chat/{url_path}" def get_index(): @@ -69,12 +92,17 @@ def get_index(): dname = Path.home() / ".aider" / "caches" / ("help." + __version__) - if dname.exists(): - storage_context = StorageContext.from_defaults( - persist_dir=dname, - ) - index = load_index_from_storage(storage_context) - else: + index = None + try: + if dname.exists(): + storage_context = StorageContext.from_defaults( + persist_dir=dname, + ) + index = load_index_from_storage(storage_context) + except (OSError, json.JSONDecodeError): + shutil.rmtree(dname) + + if index is None: parser = MarkdownNodeParser() nodes = [] diff --git a/aider/help_pats.py b/aider/help_pats.py index 6a2c20a0b..b86ef51f8 100644 --- a/aider/help_pats.py +++ b/aider/help_pats.py @@ -7,4 +7,5 @@ exclude_website_pats = [ "docs/unified-diffs.md", "docs/leaderboards/index.md", "assets/**", + "**/.DS_Store", ] diff --git a/aider/history.py b/aider/history.py index 131cf4b31..d758ccbe7 100644 --- a/aider/history.py +++ b/aider/history.py @@ -108,7 +108,9 @@ class ChatSummary: for model in self.models: try: - summary = simple_send_with_retries(model.name, summarize_messages) + summary = simple_send_with_retries( + model.name, summarize_messages, extra_params=model.extra_params + ) if summary is not None: summary = prompts.summary_prefix + summary return [dict(role="user", content=summary)] diff --git a/aider/io.py b/aider/io.py index 3a7755bc8..df6e71317 100644 --- a/aider/io.py +++ b/aider/io.py @@ -1,29 +1,45 @@ import base64 import os +import time +import webbrowser from collections import defaultdict +from dataclasses import dataclass from datetime import datetime +from io import StringIO from pathlib import Path -from prompt_toolkit import prompt -from prompt_toolkit.completion import Completer, Completion +from prompt_toolkit.completion import Completer, Completion, ThreadedCompleter +from prompt_toolkit.cursor_shapes import ModalCursorShapeConfig from prompt_toolkit.enums import EditingMode from prompt_toolkit.history import FileHistory from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.lexers import PygmentsLexer from prompt_toolkit.shortcuts import CompleteStyle, PromptSession from prompt_toolkit.styles import Style -from prompt_toolkit.validation import Validator from pygments.lexers import MarkdownLexer, guess_lexer_for_filename from pygments.token import Token -from pygments.util import ClassNotFound +from rich.columns import Columns from rich.console import Console +from rich.markdown import Markdown from rich.style import Style as RichStyle from rich.text import Text +from aider.mdstream import MarkdownStream + from .dump import dump # noqa: F401 from .utils import is_image_file +@dataclass +class ConfirmGroup: + preference: str = None + show_group: bool = True + + def __init__(self, items=None): + if items is not None: + self.show_group = len(items) > 1 + + class AutoCompleter(Completer): def __init__( self, root, rel_fnames, addable_rel_fnames, commands, encoding, abs_read_only_fnames=None @@ -57,7 +73,15 @@ class AutoCompleter(Completer): if abs_read_only_fnames: all_fnames.extend(abs_read_only_fnames) - for fname in all_fnames: + self.all_fnames = all_fnames + self.tokenized = False + + def tokenize(self): + if self.tokenized: + return + self.tokenized = True + + for fname in self.all_fnames: try: with open(fname, "r", encoding=self.encoding) as f: content = f.read() @@ -65,27 +89,37 @@ class AutoCompleter(Completer): continue try: lexer = guess_lexer_for_filename(fname, content) - except ClassNotFound: + except Exception: # On Windows, bad ref to time.clock which is deprecated continue - tokens = list(lexer.get_tokens(content)) - self.words.update(token[1] for token in tokens if token[0] in Token.Name) - def get_command_completions(self, text, words): - candidates = [] + tokens = list(lexer.get_tokens(content)) + self.words.update( + (token[1], f"`{token[1]}`") for token in tokens if token[0] in Token.Name + ) + + def get_command_completions(self, document, complete_event, text, words): if len(words) == 1 and not text[-1].isspace(): partial = words[0].lower() candidates = [cmd for cmd in self.command_names if cmd.startswith(partial)] - return candidates + for candidate in sorted(candidates): + yield Completion(candidate, start_position=-len(words[-1])) + return - if len(words) <= 1: - return [] - if text[-1].isspace(): - return [] + if len(words) <= 1 or text[-1].isspace(): + return cmd = words[0] partial = words[-1].lower() - if cmd not in self.command_names: + matches, _, _ = self.commands.matching_commands(cmd) + if len(matches) == 1: + cmd = matches[0] + elif cmd not in matches: + return + + raw_completer = self.commands.get_raw_completions(cmd) + if raw_completer: + yield from raw_completer(document, complete_event) return if cmd not in self.command_completions: @@ -98,41 +132,42 @@ class AutoCompleter(Completer): return candidates = [word for word in candidates if partial in word.lower()] - return candidates + for candidate in sorted(candidates): + yield Completion(candidate, start_position=-len(words[-1])) def get_completions(self, document, complete_event): + self.tokenize() + text = document.text_before_cursor words = text.split() if not words: return + if text and text[-1].isspace(): + # don't keep completing after a space + return + if text[0] == "/": - candidates = self.get_command_completions(text, words) - if candidates is not None: - for candidate in candidates: - yield Completion(candidate, start_position=-len(words[-1])) - return + yield from self.get_command_completions(document, complete_event, text, words) + return candidates = self.words candidates.update(set(self.fname_to_rel_fnames)) - candidates = [ - (word, f"`{word}`" if word not in self.fname_to_rel_fnames else word) - for word in candidates - ] + candidates = [word if type(word) is tuple else (word, word) for word in candidates] last_word = words[-1] + completions = [] for word_match, word_insert in candidates: if word_match.lower().startswith(last_word.lower()): + completions.append((word_insert, -len(last_word), word_match)) + rel_fnames = self.fname_to_rel_fnames.get(word_match, []) if rel_fnames: for rel_fname in rel_fnames: - yield Completion( - rel_fname, start_position=-len(last_word), display=rel_fname - ) - else: - yield Completion( - word_insert, start_position=-len(last_word), display=word_match - ) + completions.append((rel_fname, -len(last_word), rel_fname)) + + for ins, pos, match in sorted(completions): + yield Completion(ins, start_position=pos, display=match) class InputOutput: @@ -142,7 +177,7 @@ class InputOutput: def __init__( self, pretty=True, - yes=False, + yes=None, input_history_file=None, chat_history_file=None, input=None, @@ -150,11 +185,21 @@ class InputOutput: user_input_color="blue", tool_output_color=None, tool_error_color="red", + tool_warning_color="#FFA500", + assistant_output_color="blue", + completion_menu_color=None, + completion_menu_bg_color=None, + completion_menu_current_color=None, + completion_menu_current_bg_color=None, + code_theme="default", encoding="utf-8", dry_run=False, llm_history_file=None, editingmode=EditingMode.EMACS, + fancy_input=True, ): + self.placeholder = None + self.never_prompts = set() self.editingmode = editingmode no_color = os.environ.get("NO_COLOR") if no_color is not None and no_color != "": @@ -163,6 +208,14 @@ class InputOutput: self.user_input_color = user_input_color if pretty else None self.tool_output_color = tool_output_color if pretty else None self.tool_error_color = tool_error_color if pretty else None + self.tool_warning_color = tool_warning_color if pretty else None + self.assistant_output_color = assistant_output_color + self.completion_menu_color = completion_menu_color if pretty else None + self.completion_menu_bg_color = completion_menu_bg_color if pretty else None + self.completion_menu_current_color = completion_menu_current_color if pretty else None + self.completion_menu_current_bg_color = completion_menu_current_bg_color if pretty else None + + self.code_theme = code_theme self.input = input self.output = output @@ -183,19 +236,74 @@ class InputOutput: self.encoding = encoding self.dry_run = dry_run - if pretty: - self.console = Console() - else: - self.console = Console(force_terminal=False, no_color=True) - current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.append_chat_history(f"\n# aider chat started at {current_time}\n\n") + self.prompt_session = None + if fancy_input: + # Initialize PromptSession + session_kwargs = { + "input": self.input, + "output": self.output, + "lexer": PygmentsLexer(MarkdownLexer), + "editing_mode": self.editingmode, + } + if self.editingmode == EditingMode.VI: + session_kwargs["cursor"] = ModalCursorShapeConfig() + if self.input_history_file is not None: + session_kwargs["history"] = FileHistory(self.input_history_file) + try: + self.prompt_session = PromptSession(**session_kwargs) + self.console = Console() # pretty console + except Exception as err: + self.console = Console(force_terminal=False, no_color=True) + self.tool_error(f"Can't initialize prompt toolkit: {err}") # non-pretty + else: + self.console = Console(force_terminal=False, no_color=True) # non-pretty + + def _get_style(self): + style_dict = {} + if not self.pretty: + return Style.from_dict(style_dict) + + if self.user_input_color: + style_dict.setdefault("", self.user_input_color) + style_dict.update( + { + "pygments.literal.string": f"bold italic {self.user_input_color}", + } + ) + + # Conditionally add 'completion-menu' style + completion_menu_style = [] + if self.completion_menu_bg_color: + completion_menu_style.append(f"bg:{self.completion_menu_bg_color}") + if self.completion_menu_color: + completion_menu_style.append(self.completion_menu_color) + if completion_menu_style: + style_dict["completion-menu"] = " ".join(completion_menu_style) + + # Conditionally add 'completion-menu.completion.current' style + completion_menu_current_style = [] + if self.completion_menu_current_bg_color: + completion_menu_current_style.append(f"bg:{self.completion_menu_current_bg_color}") + if self.completion_menu_current_color: + completion_menu_current_style.append(self.completion_menu_current_color) + if completion_menu_current_style: + style_dict["completion-menu.completion.current"] = " ".join( + completion_menu_current_style + ) + + return Style.from_dict(style_dict) + def read_image(self, filename): try: with open(str(filename), "rb") as image_file: encoded_string = base64.b64encode(image_file.read()) return encoded_string.decode("utf-8") + except OSError as err: + self.tool_error(f"{filename}: unable to read: {err}") + return except FileNotFoundError: self.tool_error(f"{filename}: file not found error") return @@ -213,6 +321,9 @@ class InputOutput: try: with open(str(filename), "r", encoding=self.encoding) as f: return f.read() + except OSError as err: + self.tool_error(f"{filename}: unable to read: {err}") + return except FileNotFoundError: self.tool_error(f"{filename}: file not found error") return @@ -224,11 +335,43 @@ class InputOutput: self.tool_error("Use --encoding to set the unicode encoding.") return - def write_text(self, filename, content): + def write_text(self, filename, content, max_retries=5, initial_delay=0.1): + """ + Writes content to a file, retrying with progressive backoff if the file is locked. + + :param filename: Path to the file to write. + :param content: Content to write to the file. + :param max_retries: Maximum number of retries if a file lock is encountered. + :param initial_delay: Initial delay (in seconds) before the first retry. + """ if self.dry_run: return - with open(str(filename), "w", encoding=self.encoding) as f: - f.write(content) + + delay = initial_delay + for attempt in range(max_retries): + try: + with open(str(filename), "w", encoding=self.encoding) as f: + f.write(content) + return # Successfully wrote the file + except PermissionError as err: + if attempt < max_retries - 1: + time.sleep(delay) + delay *= 2 # Exponential backoff + else: + self.tool_error( + f"Unable to write file {filename} after {max_retries} attempts: {err}" + ) + raise + except OSError as err: + self.tool_error(f"Unable to write file {filename}: {err}") + raise + + def rule(self): + if self.pretty: + style = dict(style=self.user_input_color) if self.user_input_color else dict() + self.console.rule(**style) + else: + print() def get_input( self, @@ -239,16 +382,15 @@ class InputOutput: abs_read_only_fnames=None, edit_format=None, ): - if self.pretty: - style = dict(style=self.user_input_color) if self.user_input_color else dict() - self.console.rule(**style) - else: - print() + self.rule() rel_fnames = list(rel_fnames) show = "" if rel_fnames: - show = " ".join(rel_fnames) + "\n" + rel_read_only_fnames = [ + get_rel_fname(fname, root) for fname in (abs_read_only_fnames or []) + ] + show = self.format_files_for_input(rel_fnames, rel_read_only_fnames) if edit_format: show += edit_format show += "> " @@ -256,62 +398,87 @@ class InputOutput: inp = "" multiline_input = False - if self.user_input_color: - style = Style.from_dict( - { - "": self.user_input_color, - "pygments.literal.string": f"bold italic {self.user_input_color}", - } - ) - else: - style = None + style = self._get_style() - completer_instance = AutoCompleter( - root, - rel_fnames, - addable_rel_fnames, - commands, - self.encoding, - abs_read_only_fnames=abs_read_only_fnames, + completer_instance = ThreadedCompleter( + AutoCompleter( + root, + rel_fnames, + addable_rel_fnames, + commands, + self.encoding, + abs_read_only_fnames=abs_read_only_fnames, + ) ) + kb = KeyBindings() + + @kb.add("c-space") + def _(event): + "Ignore Ctrl when pressing space bar" + event.current_buffer.insert_text(" ") + + @kb.add("escape", "c-m", eager=True) + def _(event): + event.current_buffer.insert_text("\n") + while True: if multiline_input: show = ". " - session_kwargs = { - "message": show, - "completer": completer_instance, - "reserve_space_for_menu": 4, - "complete_style": CompleteStyle.MULTI_COLUMN, - "input": self.input, - "output": self.output, - "lexer": PygmentsLexer(MarkdownLexer), - } - if style: - session_kwargs["style"] = style + try: + if self.prompt_session: + # Use placeholder if set, then clear it + default = self.placeholder or "" + self.placeholder = None - if self.input_history_file is not None: - session_kwargs["history"] = FileHistory(self.input_history_file) + line = self.prompt_session.prompt( + show, + default=default, + completer=completer_instance, + reserve_space_for_menu=4, + complete_style=CompleteStyle.MULTI_COLUMN, + style=style, + key_bindings=kb, + ) + else: + line = input(show) + except UnicodeEncodeError as err: + self.tool_error(str(err)) + return "" - kb = KeyBindings() - - @kb.add("escape", "c-m", eager=True) - def _(event): - event.current_buffer.insert_text("\n") - - session = PromptSession( - key_bindings=kb, editing_mode=self.editingmode, **session_kwargs - ) - line = session.prompt() - - if line and line[0] == "{" and not multiline_input: - multiline_input = True - inp += line[1:] + "\n" + if line.strip("\r\n") and not multiline_input: + stripped = line.strip("\r\n") + if stripped == "{": + multiline_input = True + multiline_tag = None + inp += "" + elif stripped[0] == "{": + # Extract tag if it exists (only alphanumeric chars) + tag = "".join(c for c in stripped[1:] if c.isalnum()) + if stripped == "{" + tag: + multiline_input = True + multiline_tag = tag + inp += "" + else: + inp = line + break + else: + inp = line + break continue - elif line and line[-1] == "}" and multiline_input: - inp += line[:-1] + "\n" - break + elif multiline_input and line.strip(): + if multiline_tag: + # Check if line is exactly "tag}" + if line.strip("\r\n") == f"{multiline_tag}}}": + break + else: + inp += line + "\n" + # Check if line is exactly "}" + elif line.strip("\r\n") == "}": + break + else: + inp += line + "\n" elif multiline_input: inp += line + "\n" else: @@ -325,10 +492,13 @@ class InputOutput: def add_to_input_history(self, inp): if not self.input_history_file: return - FileHistory(self.input_history_file).append_string(inp) - # Also add to the in-memory history if it exists - if hasattr(self, "session") and hasattr(self.session, "history"): - self.session.history.append_string(inp) + try: + FileHistory(self.input_history_file).append_string(inp) + # Also add to the in-memory history if it exists + if self.prompt_session and self.prompt_session.history: + self.prompt_session.history.append_string(inp) + except OSError as err: + self.tool_warning(f"Unable to write to input history file: {err}") def get_input_history(self): if not self.input_history_file: @@ -345,10 +515,17 @@ class InputOutput: log_file.write(f"{role.upper()} {timestamp}\n") log_file.write(content + "\n") + def display_user_input(self, inp): + if self.pretty and self.user_input_color: + style = dict(style=self.user_input_color) + else: + style = dict() + + self.console.print(Text(inp), **style) + def user_input(self, inp, log_only=True): - if not log_only and self.pretty: - style = dict(style=self.user_input_color) if self.user_input_color else dict() - self.console.print(Text(inp), **style) + if not log_only: + self.display_user_input(inp) prefix = "####" if inp: @@ -368,15 +545,49 @@ class InputOutput: hist = "\n" + content.strip() + "\n\n" self.append_chat_history(hist) - def confirm_ask(self, question, default="y", subject=None, explicit_yes_required=False): + def offer_url(self, url, prompt="Open URL for more info?", allow_never=True): + """Offer to open a URL in the browser, returns True if opened.""" + if url in self.never_prompts: + return False + if self.confirm_ask(prompt, subject=url, allow_never=allow_never): + webbrowser.open(url) + return True + return False + + def confirm_ask( + self, + question, + default="y", + subject=None, + explicit_yes_required=False, + group=None, + allow_never=False, + ): self.num_user_asks += 1 - if default == "y": - question += " [Y/n] " - elif default == "n": - question += " [y/N] " - else: - question += " [y/n] " + question_id = (question, subject) + + if question_id in self.never_prompts: + return False + + if group and not group.show_group: + group = None + if group: + allow_never = True + + valid_responses = ["yes", "no"] + options = " (Y)es/(N)o" + if group: + if not explicit_yes_required: + options += "/(A)ll" + valid_responses.append("all") + options += "/(S)kip all" + valid_responses.append("skip") + if allow_never: + options += "/(D)on't ask again" + valid_responses.append("don't") + + question += options + " [Yes]: " if subject: self.tool_output() @@ -389,37 +600,64 @@ class InputOutput: else: self.tool_output(subject, bold=True) - if self.pretty and self.user_input_color: - style = {"": self.user_input_color} - else: - style = dict() + style = self._get_style() - def is_yesno(text): - return "yes".startswith(text.lower()) or "no".startswith(text.lower()) - - validator = Validator.from_callable( - is_yesno, - error_message="Answer yes or no.", - move_cursor_to_end=True, - ) + def is_valid_response(text): + if not text: + return True + return text.lower() in valid_responses if self.yes is True: res = "n" if explicit_yes_required else "y" elif self.yes is False: res = "n" + elif group and group.preference: + res = group.preference + self.user_input(f"{question}{res}", log_only=False) else: - res = prompt( - question, - style=Style.from_dict(style), - validator=validator, - ) - if not res and default: - res = default + while True: + if self.prompt_session: + res = self.prompt_session.prompt( + question, + style=style, + ) + else: + res = input(question) - res = res.lower().strip() - is_yes = res in ("y", "yes") + if not res: + res = "y" # Default to Yes if no input + break + res = res.lower() + good = any(valid_response.startswith(res) for valid_response in valid_responses) + if good: + break - hist = f"{question.strip()} {'y' if is_yes else 'n'}" + error_message = f"Please answer with one of: {', '.join(valid_responses)}" + self.tool_error(error_message) + + res = res.lower()[0] + + if res == "d" and allow_never: + self.never_prompts.add(question_id) + hist = f"{question.strip()} {res}" + self.append_chat_history(hist, linebreak=True, blockquote=True) + return False + + if explicit_yes_required: + is_yes = res == "y" + else: + is_yes = res in ("y", "a") + + is_all = res == "a" and group is not None and not explicit_yes_required + is_skip = res == "s" and group is not None + + if group: + if is_all and not explicit_yes_required: + group.preference = "all" + elif is_skip: + group.preference = "skip" + + hist = f"{question.strip()} {res}" self.append_chat_history(hist, linebreak=True, blockquote=True) return is_yes @@ -431,17 +669,17 @@ class InputOutput: self.tool_output() self.tool_output(subject, bold=True) - if self.pretty and self.user_input_color: - style = Style.from_dict({"": self.user_input_color}) - else: - style = None + style = self._get_style() if self.yes is True: res = "yes" elif self.yes is False: res = "no" else: - res = prompt(question + " ", default=default, style=style) + if self.prompt_session: + res = self.prompt_session.prompt(question + " ", default=default, style=style) + else: + res = input(question + " ") hist = f"{question.strip()} {res.strip()}" self.append_chat_history(hist, linebreak=True, blockquote=True) @@ -450,36 +688,72 @@ class InputOutput: return res - def tool_error(self, message="", strip=True): - self.num_error_outputs += 1 - + def _tool_message(self, message="", strip=True, color=None): if message.strip(): if "\n" in message: for line in message.splitlines(): self.append_chat_history(line, linebreak=True, blockquote=True, strip=strip) else: - if strip: - hist = message.strip() - else: - hist = message + hist = message.strip() if strip else message self.append_chat_history(hist, linebreak=True, blockquote=True) message = Text(message) - style = dict(style=self.tool_error_color) if self.tool_error_color else dict() + style = dict(style=color) if self.pretty and color else dict() self.console.print(message, **style) + def tool_error(self, message="", strip=True): + self.num_error_outputs += 1 + self._tool_message(message, strip, self.tool_error_color) + + def tool_warning(self, message="", strip=True): + self._tool_message(message, strip, self.tool_warning_color) + def tool_output(self, *messages, log_only=False, bold=False): if messages: hist = " ".join(messages) hist = f"{hist.strip()}" self.append_chat_history(hist, linebreak=True, blockquote=True) - if not log_only: - messages = list(map(Text, messages)) - style = dict(color=self.tool_output_color) if self.tool_output_color else dict() + if log_only: + return + + messages = list(map(Text, messages)) + style = dict() + if self.pretty: + if self.tool_output_color: + style["color"] = self.tool_output_color style["reverse"] = bold - style = RichStyle(**style) - self.console.print(*messages, style=style) + + style = RichStyle(**style) + self.console.print(*messages, style=style) + + def get_assistant_mdstream(self): + mdargs = dict(style=self.assistant_output_color, code_theme=self.code_theme) + mdStream = MarkdownStream(mdargs=mdargs) + return mdStream + + def assistant_output(self, message, pretty=None): + show_resp = message + + # Coder will force pretty off if fence is not triple-backticks + if pretty is None: + pretty = self.pretty + + if pretty: + show_resp = Markdown( + message, style=self.assistant_output_color, code_theme=self.code_theme + ) + else: + show_resp = Text(message or "") + + self.console.print(show_resp) + + def set_placeholder(self, placeholder): + """Set a one-time placeholder text for the next input prompt.""" + self.placeholder = placeholder + + def print(self, message=""): + print(message) def append_chat_history(self, text, linebreak=False, blockquote=False, strip=True): if blockquote: @@ -493,5 +767,58 @@ class InputOutput: if not text.endswith("\n"): text += "\n" if self.chat_history_file is not None: - with self.chat_history_file.open("a", encoding=self.encoding) as f: - f.write(text) + try: + with self.chat_history_file.open("a", encoding=self.encoding, errors="ignore") as f: + f.write(text) + except (PermissionError, OSError) as err: + print(f"Warning: Unable to write to chat history file {self.chat_history_file}.") + print(err) + self.chat_history_file = None # Disable further attempts to write + + def format_files_for_input(self, rel_fnames, rel_read_only_fnames): + if not self.pretty: + read_only_files = [] + for full_path in sorted(rel_read_only_fnames or []): + read_only_files.append(f"{full_path} (read only)") + + editable_files = [] + for full_path in sorted(rel_fnames): + if full_path in rel_read_only_fnames: + continue + editable_files.append(f"{full_path}") + + return "\n".join(read_only_files + editable_files) + "\n" + + output = StringIO() + console = Console(file=output, force_terminal=False) + + read_only_files = sorted(rel_read_only_fnames or []) + editable_files = [f for f in sorted(rel_fnames) if f not in rel_read_only_fnames] + + if read_only_files: + files_with_label = ["Readonly:"] + read_only_files + read_only_output = StringIO() + Console(file=read_only_output, force_terminal=False).print(Columns(files_with_label)) + read_only_lines = read_only_output.getvalue().splitlines() + console.print(Columns(files_with_label)) + + if editable_files: + files_with_label = editable_files + if read_only_files: + files_with_label = ["Editable:"] + editable_files + editable_output = StringIO() + Console(file=editable_output, force_terminal=False).print(Columns(files_with_label)) + editable_lines = editable_output.getvalue().splitlines() + + if len(read_only_lines) > 1 or len(editable_lines) > 1: + console.print() + console.print(Columns(files_with_label)) + + return output.getvalue() + + +def get_rel_fname(fname, root): + try: + return os.path.relpath(fname, root) + except ValueError: + return fname diff --git a/aider/linter.py b/aider/linter.py index cbdcee2c7..529cacb9d 100644 --- a/aider/linter.py +++ b/aider/linter.py @@ -35,7 +35,10 @@ class Linter: def get_rel_fname(self, fname): if self.root: - return os.path.relpath(fname, self.root) + try: + return os.path.relpath(fname, self.root) + except ValueError: + return fname else: return fname @@ -43,14 +46,18 @@ class Linter: cmd += " " + rel_fname cmd = cmd.split() - process = subprocess.Popen( - cmd, - cwd=self.root, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - encoding=self.encoding, - errors="replace", - ) + try: + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + encoding=self.encoding, + errors="replace", + cwd=self.root, + ) + except OSError as err: + print(f"Unable to execute lint command: {err}") + return stdout, _ = process.communicate() errors = stdout if process.returncode == 0: @@ -76,7 +83,11 @@ class Linter: def lint(self, fname, cmd=None): rel_fname = self.get_rel_fname(fname) - code = Path(fname).read_text(self.encoding) + try: + code = Path(fname).read_text(encoding=self.encoding, errors="replace") + except OSError as err: + print(f"Unable to read {fname}: {err}") + return if cmd: cmd = cmd.strip() @@ -141,12 +152,12 @@ class Linter: try: result = subprocess.run( flake8_cmd, - cwd=self.root, capture_output=True, text=True, check=False, encoding=self.encoding, errors="replace", + cwd=self.root, ) errors = result.stdout + result.stderr except Exception as e: @@ -198,10 +209,24 @@ def basic_lint(fname, code): if not lang: return - parser = get_parser(lang) + # Tree-sitter linter is not capable of working with typescript #1132 + if lang == "typescript": + return + + try: + parser = get_parser(lang) + except Exception as err: + print(f"Unable to load parser: {err}") + return + tree = parser.parse(bytes(code, "utf-8")) - errors = traverse_tree(tree.root_node) + try: + errors = traverse_tree(tree.root_node) + except RecursionError: + print(f"Unable to lint {fname} due to RecursionError") + return + if not errors: return diff --git a/aider/llm.py b/aider/llm.py index c676b89b3..f750f41af 100644 --- a/aider/llm.py +++ b/aider/llm.py @@ -9,6 +9,7 @@ AIDER_APP_NAME = "Aider" os.environ["OR_SITE_URL"] = AIDER_SITE_URL os.environ["OR_APP_NAME"] = AIDER_APP_NAME +os.environ["LITELLM_MODE"] = "PRODUCTION" # `import litellm` takes 1.5 seconds, defer it! @@ -31,6 +32,7 @@ class LazyLiteLLM: self._lazy_module.suppress_debug_info = True self._lazy_module.set_verbose = False self._lazy_module.drop_params = True + self._lazy_module._logging._disable_debugging() litellm = LazyLiteLLM() diff --git a/aider/main.py b/aider/main.py index f25c56527..29c6a9efb 100644 --- a/aider/main.py +++ b/aider/main.py @@ -1,33 +1,60 @@ import configparser +import json import os import re import sys import threading +import traceback +import webbrowser +from dataclasses import fields from pathlib import Path import git +import importlib_resources from dotenv import load_dotenv from prompt_toolkit.enums import EditingMode -from aider import __version__, models, utils +from aider import __version__, models, urls, utils +from aider.analytics import Analytics from aider.args import get_parser from aider.coders import Coder +from aider.coders.base_coder import UnknownEditFormat from aider.commands import Commands, SwitchCoder +from aider.format_settings import format_settings, scrub_sensitive_info from aider.history import ChatSummary from aider.io import InputOutput from aider.llm import litellm # noqa: F401; properly init litellm on launch -from aider.repo import GitRepo -from aider.versioncheck import check_version +from aider.models import ModelSettings +from aider.repo import ANY_GIT_ERROR, GitRepo +from aider.report import report_uncaught_exceptions +from aider.versioncheck import check_version, install_from_main_branch, install_upgrade from .dump import dump # noqa: F401 +def check_config_files_for_yes(config_files): + found = False + for config_file in config_files: + if Path(config_file).exists(): + try: + with open(config_file, "r") as f: + for line in f: + if line.strip().startswith("yes:"): + print("Configuration error detected.") + print(f"The file {config_file} contains a line starting with 'yes:'") + print("Please replace 'yes:' with 'yes-always:' in this file.") + found = True + except Exception: + pass + return found + + def get_git_root(): """Try and guess the git repo, since the conf.yml can be at the repo root""" try: repo = git.Repo(search_parent_directories=True) return repo.working_tree_dir - except git.InvalidGitRepositoryError: + except (git.InvalidGitRepositoryError, FileNotFoundError): return None @@ -36,7 +63,7 @@ def guessed_wrong_repo(io, git_root, fnames, git_dname): try: check_repo = Path(GitRepo(io, fnames, git_dname).root).resolve() - except FileNotFoundError: + except (OSError,) + ANY_GIT_ERROR: return # we had no guess, rely on the "true" repo result @@ -50,15 +77,40 @@ def guessed_wrong_repo(io, git_root, fnames, git_dname): return str(check_repo) -def setup_git(git_root, io): - repo = None - if git_root: - repo = git.Repo(git_root) - elif io.confirm_ask("No git repo found, create one to track GPT's changes (recommended)?"): - git_root = str(Path.cwd().resolve()) +def make_new_repo(git_root, io): + try: repo = git.Repo.init(git_root) - io.tool_output("Git repository created in the current working directory.") check_gitignore(git_root, io, False) + except ANY_GIT_ERROR as err: # issue #1233 + io.tool_error(f"Unable to create git repo in {git_root}") + io.tool_output(str(err)) + return + + io.tool_output(f"Git repository created in {git_root}") + return repo + + +def setup_git(git_root, io): + try: + cwd = Path.cwd() + except OSError: + cwd = None + + repo = None + + if git_root: + try: + repo = git.Repo(git_root) + except ANY_GIT_ERROR: + pass + elif cwd == Path.home(): + io.tool_warning("You should probably run aider in a directory, not your home dir.") + return + elif cwd and io.confirm_ask( + "No git repo found, create one to track aider's changes (recommended)?" + ): + git_root = str(cwd.resolve()) + repo = make_new_repo(git_root, io) if not repo: return @@ -72,7 +124,7 @@ def setup_git(git_root, io): pass try: user_email = config.get_value("user", "email", None) - except configparser.NoSectionError: + except (configparser.NoSectionError, configparser.NoOptionError): pass if user_name and user_email: @@ -81,10 +133,10 @@ def setup_git(git_root, io): with repo.config_writer() as git_config: if not user_name: git_config.set_value("user", "name", "Your Name") - io.tool_error('Update git name with: git config user.name "Your Name"') + io.tool_warning('Update git name with: git config user.name "Your Name"') if not user_email: git_config.set_value("user", "email", "you@example.com") - io.tool_error('Update git email with: git config user.email "you@example.com"') + io.tool_warning('Update git email with: git config user.email "you@example.com"') return repo.working_tree_dir @@ -95,60 +147,51 @@ def check_gitignore(git_root, io, ask=True): try: repo = git.Repo(git_root) - if repo.ignored(".aider"): + if repo.ignored(".aider") and repo.ignored(".env"): return - except git.exc.InvalidGitRepositoryError: + except ANY_GIT_ERROR: pass - pat = ".aider*" + patterns = [".aider*", ".env"] + patterns_to_add = [] gitignore_file = Path(git_root) / ".gitignore" if gitignore_file.exists(): - content = io.read_text(gitignore_file) - if content is None: - return - if pat in content.splitlines(): + try: + content = io.read_text(gitignore_file) + if content is None: + return + existing_lines = content.splitlines() + for pat in patterns: + if pat not in existing_lines: + patterns_to_add.append(pat) + except OSError as e: + io.tool_error(f"Error when trying to read {gitignore_file}: {e}") return else: content = "" + patterns_to_add = patterns - if ask and not io.confirm_ask(f"Add {pat} to .gitignore (recommended)?"): + if not patterns_to_add: + return + + if ask and not io.confirm_ask(f"Add {', '.join(patterns_to_add)} to .gitignore (recommended)?"): return if content and not content.endswith("\n"): content += "\n" - content += pat + "\n" - io.write_text(gitignore_file, content) + content += "\n".join(patterns_to_add) + "\n" - io.tool_output(f"Added {pat} to .gitignore") - - -def format_settings(parser, args): - show = scrub_sensitive_info(args, parser.format_values()) - # clean up the headings for consistency w/ new lines - heading_env = "Environment Variables:" - heading_defaults = "Defaults:" - if heading_env in show: - show = show.replace(heading_env, "\n" + heading_env) - show = show.replace(heading_defaults, "\n" + heading_defaults) - show += "\n" - show += "Option settings:\n" - for arg, val in sorted(vars(args).items()): - if val: - val = scrub_sensitive_info(args, str(val)) - show += f" - {arg}: {val}\n" # noqa: E221 - return show - - -def scrub_sensitive_info(args, text): - # Replace sensitive information with last 4 characters - if text and args.openai_api_key: - last_4 = args.openai_api_key[-4:] - text = text.replace(args.openai_api_key, f"...{last_4}") - if text and args.anthropic_api_key: - last_4 = args.anthropic_api_key[-4:] - text = text.replace(args.anthropic_api_key, f"...{last_4}") - return text + try: + io.write_text(gitignore_file, content) + io.tool_output(f"Added {', '.join(patterns_to_add)} to .gitignore") + except OSError as e: + io.tool_error(f"Error when trying to write to {gitignore_file}: {e}") + io.tool_output( + "Try running with appropriate permissions or manually add these patterns to .gitignore:" + ) + for pattern in patterns_to_add: + io.tool_output(f" {pattern}") def check_streamlit_install(io): @@ -178,7 +221,10 @@ def launch_gui(args): "--server.runOnSave=false", ] - if "-dev" in __version__: + # https://github.com/Aider-AI/aider/issues/2193 + is_dev = "-dev" in str(__version__) + + if is_dev: print("Watching for file changes.") else: st_args += [ @@ -218,24 +264,31 @@ def parse_lint_cmds(lint_cmds, io): res[lang] = cmd else: io.tool_error(f'Unable to parse --lint-cmd "{lint_cmd}"') - io.tool_error('The arg should be "language: cmd --args ..."') - io.tool_error('For example: --lint-cmd "python: flake8 --select=E9"') + io.tool_output('The arg should be "language: cmd --args ..."') + io.tool_output('For example: --lint-cmd "python: flake8 --select=E9"') err = True if err: return return res -def generate_search_path_list(default_fname, git_root, command_line_file): +def generate_search_path_list(default_file, git_root, command_line_file): files = [] - default_file = Path(default_fname) files.append(Path.home() / default_file) # homedir if git_root: files.append(Path(git_root) / default_file) # git root - files.append(default_file.resolve()) + files.append(default_file) if command_line_file: files.append(command_line_file) - files = [Path(fn).resolve() for fn in files] + + resolved_files = [] + for fn in files: + try: + resolved_files.append(Path(fn).resolve()) + except OSError: + pass + + files = resolved_files files.reverse() uniq = [] for fn in files: @@ -275,7 +328,7 @@ def register_models(git_root, model_settings_fname, io, verbose=False): return None -def load_dotenv_files(git_root, dotenv_fname): +def load_dotenv_files(git_root, dotenv_fname, encoding="utf-8"): dotenv_files = generate_search_path_list( ".env", git_root, @@ -283,14 +336,25 @@ def load_dotenv_files(git_root, dotenv_fname): ) loaded = [] for fname in dotenv_files: - if Path(fname).exists(): - loaded.append(fname) - load_dotenv(fname, override=True) + try: + if Path(fname).exists(): + load_dotenv(fname, override=True, encoding=encoding) + loaded.append(fname) + except OSError as e: + print(f"OSError loading {fname}: {e}") + except Exception as e: + print(f"Error loading {fname}: {e}") return loaded def register_litellm_models(git_root, model_metadata_fname, io, verbose=False): - model_metatdata_files = generate_search_path_list( + model_metatdata_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_metatdata_files += generate_search_path_list( ".aider.model.metadata.json", git_root, model_metadata_fname ) @@ -305,7 +369,42 @@ def register_litellm_models(git_root, model_metadata_fname, io, verbose=False): return 1 +def sanity_check_repo(repo, io): + if not repo: + return True + + if not repo.repo.working_tree_dir: + io.tool_error("The git repo does not seem to have a working tree?") + return False + + bad_ver = False + try: + repo.get_tracked_files() + if not repo.git_repo_error: + return True + error_msg = str(repo.git_repo_error) + except ANY_GIT_ERROR as exc: + error_msg = str(exc) + bad_ver = "version in (1, 2)" in error_msg + except AssertionError as exc: + error_msg = str(exc) + bad_ver = True + + if bad_ver: + io.tool_error("Aider only works with git repos with version number 1 or 2.") + io.tool_output("You may be able to convert your repo: git update-index --index-version=2") + io.tool_output("Or run aider --no-git to proceed without using git.") + io.offer_url(urls.git_index_version, "Open documentation url for more info?") + return False + + io.tool_error("Unable to read git repository, it may be corrupt?") + io.tool_output(error_msg) + return False + + def main(argv=None, input=None, output=None, force_git_root=None, return_coder=False): + report_uncaught_exceptions() + if argv is None: argv = sys.argv[1:] @@ -316,7 +415,12 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F conf_fname = Path(".aider.conf.yml") - default_config_files = [conf_fname.resolve()] # CWD + default_config_files = [] + try: + default_config_files += [conf_fname.resolve()] # CWD + except OSError: + pass + if git_root: git_conf = Path(git_root) / conf_fname # git root if git_conf not in default_config_files: @@ -325,7 +429,13 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F default_config_files = list(map(str, default_config_files)) parser = get_parser(default_config_files, git_root) - args, unknown = parser.parse_known_args(argv) + try: + args, unknown = parser.parse_known_args(argv) + except AttributeError as e: + if all(word in str(e) for word in ["bool", "object", "has", "no", "attribute", "strip"]): + if check_config_files_for_yes(default_config_files): + return 1 + raise e if args.verbose: print("Config files search order, if no --config:") @@ -336,56 +446,109 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F default_config_files.reverse() parser = get_parser(default_config_files, git_root) + args, unknown = parser.parse_known_args(argv) # Load the .env file specified in the arguments - loaded_dotenvs = load_dotenv_files(git_root, args.env_file) + loaded_dotenvs = load_dotenv_files(git_root, args.env_file, args.encoding) # Parse again to include any arguments that might have been defined in .env args = parser.parse_args(argv) + if args.analytics_disable: + analytics = Analytics(permanently_disable=True) + print("Analytics have been permanently disabled.") + if not args.verify_ssl: import httpx + os.environ["SSL_VERIFY"] = "" litellm._load_litellm() litellm._lazy_module.client_session = httpx.Client(verify=False) + litellm._lazy_module.aclient_session = httpx.AsyncClient(verify=False) if args.dark_mode: args.user_input_color = "#32FF32" args.tool_error_color = "#FF3333" + args.tool_warning_color = "#FFFF00" args.assistant_output_color = "#00FFFF" args.code_theme = "monokai" if args.light_mode: args.user_input_color = "green" args.tool_error_color = "red" + args.tool_warning_color = "#FFA500" args.assistant_output_color = "blue" args.code_theme = "default" - if return_coder and args.yes is None: - args.yes = True + if return_coder and args.yes_always is None: + args.yes_always = True editing_mode = EditingMode.VI if args.vim else EditingMode.EMACS - io = InputOutput( - args.pretty, - args.yes, - args.input_history_file, - args.chat_history_file, - input=input, - output=output, - user_input_color=args.user_input_color, - tool_output_color=args.tool_output_color, - tool_error_color=args.tool_error_color, - dry_run=args.dry_run, - encoding=args.encoding, - llm_history_file=args.llm_history_file, - editingmode=editing_mode, - ) + def get_io(pretty): + return InputOutput( + pretty, + args.yes_always, + args.input_history_file, + args.chat_history_file, + input=input, + output=output, + user_input_color=args.user_input_color, + tool_output_color=args.tool_output_color, + tool_warning_color=args.tool_warning_color, + tool_error_color=args.tool_error_color, + completion_menu_color=args.completion_menu_color, + completion_menu_bg_color=args.completion_menu_bg_color, + completion_menu_current_color=args.completion_menu_current_color, + completion_menu_current_bg_color=args.completion_menu_current_bg_color, + assistant_output_color=args.assistant_output_color, + code_theme=args.code_theme, + dry_run=args.dry_run, + encoding=args.encoding, + llm_history_file=args.llm_history_file, + editingmode=editing_mode, + fancy_input=args.fancy_input, + ) + + io = get_io(args.pretty) + try: + io.rule() + except UnicodeEncodeError as err: + if not io.pretty: + raise err + io = get_io(False) + io.tool_warning("Terminal does not support pretty output (UnicodeDecodeError)") + + analytics = Analytics(logfile=args.analytics_log, permanently_disable=args.analytics_disable) + if args.analytics is not False: + if analytics.need_to_ask(args.analytics): + io.tool_output( + "Aider respects your privacy and never collects your code, chat messages, keys or" + " personal info." + ) + io.tool_output(f"For more info: {urls.analytics}") + disable = not io.confirm_ask( + "Allow collection of anonymous analytics to help improve aider?" + ) + + analytics.asked_opt_in = True + if disable: + analytics.disable(permanently=True) + io.tool_output("Analytics have been permanently disabled.") + + analytics.save_data() + io.tool_output() + + # This is a no-op if the user has opted out + analytics.enable() + + analytics.event("launched") if args.gui and not return_coder: if not check_streamlit_install(io): return + analytics.event("gui session") launch_gui(argv) return @@ -395,7 +558,14 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F all_files = args.files + (args.file or []) fnames = [str(Path(fn).resolve()) for fn in all_files] - read_only_fnames = [str(Path(fn).resolve()) for fn in (args.read or [])] + read_only_fnames = [] + for fn in args.read or []: + path = Path(fn).resolve() + if path.is_dir(): + read_only_fnames.extend(str(f) for f in path.rglob("*") if f.is_file()) + else: + read_only_fnames.append(str(path)) + if len(all_files) > 1: good = True for fname in all_files: @@ -403,7 +573,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F io.tool_error(f"{fname} is a directory, not provided alone.") good = False if not good: - io.tool_error( + io.tool_output( "Provide either a single directory of a git repo, or a list of one or more files." ) return 1 @@ -430,11 +600,19 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F update_available = check_version(io, just_check=True, verbose=args.verbose) return 0 if not update_available else 1 + if args.install_main_branch: + success = install_from_main_branch(io) + return 0 if success else 1 + + if args.upgrade: + success = install_upgrade(io) + return 0 if success else 1 + if args.check_update: check_version(io, verbose=args.verbose) - if args.models: - models.print_matching_models(io, args.models) + if args.list_models: + models.print_matching_models(io, args.list_models) return 0 if args.git: @@ -450,6 +628,9 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F cmd_line = scrub_sensitive_info(args, cmd_line) io.tool_output(cmd_line, log_only=True) + is_first_run = is_first_run_of_new_version(io, verbose=args.verbose) + check_and_load_imports(io, is_first_run, verbose=args.verbose) + if args.anthropic_api_key: os.environ["ANTHROPIC_API_KEY"] = args.anthropic_api_key @@ -467,19 +648,55 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F register_models(git_root, args.model_settings_file, io, verbose=args.verbose) register_litellm_models(git_root, args.model_metadata_file, io, verbose=args.verbose) + # Process any command line aliases + if args.alias: + for alias_def in args.alias: + # Split on first colon only + parts = alias_def.split(":", 1) + if len(parts) != 2: + io.tool_error(f"Invalid alias format: {alias_def}") + io.tool_output("Format should be: alias:model-name") + return 1 + alias, model = parts + models.MODEL_ALIASES[alias.strip()] = model.strip() + if not args.model: args.model = "gpt-4o-2024-08-06" if os.environ.get("ANTHROPIC_API_KEY"): - args.model = "claude-3-5-sonnet-20240620" + args.model = "claude-3-5-sonnet-20241022" - main_model = models.Model(args.model, weak_model=args.weak_model) + main_model = models.Model( + args.model, + weak_model=args.weak_model, + editor_model=args.editor_model, + editor_edit_format=args.editor_edit_format, + ) + + if args.verbose: + io.tool_output("Model metadata:") + io.tool_output(json.dumps(main_model.info, indent=4)) + + io.tool_output("Model settings:") + for attr in sorted(fields(ModelSettings), key=lambda x: x.name): + val = getattr(main_model, attr.name) + val = json.dumps(val, indent=4) + io.tool_output(f"{attr.name}: {val}") lint_cmds = parse_lint_cmds(args.lint_cmd, io) if lint_cmds is None: return 1 if args.show_model_warnings: - models.sanity_check_models(io, main_model) + problem = models.sanity_check_models(io, main_model) + if problem: + analytics.event("model warning", main_model=main_model) + io.tool_output("You can skip this check with --no-show-model-warnings") + + try: + io.offer_url(urls.model_warnings, "Open documentation url for more info?") + io.tool_output() + except KeyboardInterrupt: + return 1 repo = None if args.git: @@ -500,7 +717,19 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F except FileNotFoundError: pass - commands = Commands(io, None, verify_ssl=args.verify_ssl) + if not args.skip_sanity_check_repo: + if not sanity_check_repo(repo, io): + return 1 + + commands = Commands( + io, + None, + verify_ssl=args.verify_ssl, + args=args, + parser=parser, + verbose=args.verbose, + editor=args.editor, + ) summarizer = ChatSummary( [main_model.weak_model, main_model], @@ -510,6 +739,13 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F if args.cache_prompts and args.map_refresh == "auto": args.map_refresh = "files" + if not main_model.streaming: + if args.stream: + io.tool_warning( + f"Warning: Streaming is not supported by {main_model.name}. Disabling streaming." + ) + args.stream = False + try: coder = Coder.create( main_model=main_model, @@ -524,8 +760,6 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F dry_run=args.dry_run, map_tokens=args.map_tokens, verbose=args.verbose, - assistant_output_color=args.assistant_output_color, - code_theme=args.code_theme, stream=args.stream, use_git=args.git, restore_chat_history=args.restore_chat_history, @@ -535,10 +769,19 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F test_cmd=args.test_cmd, commands=commands, summarizer=summarizer, + analytics=analytics, map_refresh=args.map_refresh, cache_prompts=args.cache_prompts, map_mul_no_files=args.map_multiplier_no_files, + num_cache_warming_pings=args.cache_keepalive_pings, + suggest_shell_commands=args.suggest_shell_commands, + chat_language=args.chat_language, + detect_urls=args.detect_urls, ) + except UnknownEditFormat as err: + io.tool_error(str(err)) + io.offer_url(urls.edit_formats, "Open documentation about edit formats?") + return 1 except ValueError as err: io.tool_error(str(err)) return 1 @@ -546,14 +789,13 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F if return_coder: return coder - io.tool_output() coder.show_announcements() if args.show_prompts: coder.cur_messages += [ dict(role="user", content="Hello!"), ] - messages = coder.format_messages() + messages = coder.format_messages().all_messages() utils.show_messages(messages) return @@ -591,20 +833,39 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F coder.apply_updates() return + if args.apply_clipboard_edits: + args.edit_format = main_model.editor_edit_format + args.message = "/paste" + if "VSCODE_GIT_IPC_HANDLE" in os.environ: args.pretty = False io.tool_output("VSCode terminal detected, pretty output has been disabled.") io.tool_output('Use /help for help, run "aider --help" to see cmd line args') + if args.show_release_notes is True: + io.tool_output(f"Opening release notes: {urls.release_notes}") + io.tool_output() + webbrowser.open(urls.release_notes) + elif args.show_release_notes is None and is_first_run: + io.tool_output() + io.offer_url( + urls.release_notes, + "Would you like to see what's new in this version?", + allow_never=False, + ) + if git_root and Path.cwd().resolve() != Path(git_root).resolve(): - io.tool_error( + io.tool_warning( "Note: in-chat filenames are always relative to the git working dir, not the current" " working dir." ) - io.tool_error(f"Cur working dir: {Path.cwd()}") - io.tool_error(f"Git working dir: {git_root}") + io.tool_output(f"Cur working dir: {Path.cwd()}") + io.tool_output(f"Git working dir: {git_root}") + + if args.load: + commands.cmd_load(args.load) if args.message: io.add_to_input_history(args.message) @@ -631,9 +892,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F if args.exit: return - thread = threading.Thread(target=load_slow_imports) - thread.daemon = True - thread.start() + analytics.event("cli session", main_model=main_model, edit_format=main_model.edit_format) while True: try: @@ -651,19 +910,89 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F coder.show_announcements() -def load_slow_imports(): +def is_first_run_of_new_version(io, verbose=False): + """Check if this is the first run of a new version/executable combination""" + installs_file = Path.home() / ".aider" / "installs.json" + key = (__version__, sys.executable) + + if verbose: + io.tool_output( + f"Checking imports for version {__version__} and executable {sys.executable}" + ) + io.tool_output(f"Installs file: {installs_file}") + + try: + if installs_file.exists(): + with open(installs_file, "r") as f: + installs = json.load(f) + if verbose: + io.tool_output("Installs file exists and loaded") + else: + installs = {} + if verbose: + io.tool_output("Installs file does not exist, creating new dictionary") + + is_first_run = str(key) not in installs + + if is_first_run: + installs[str(key)] = True + installs_file.parent.mkdir(parents=True, exist_ok=True) + with open(installs_file, "w") as f: + json.dump(installs, f, indent=4) + + return is_first_run + + except Exception as e: + io.tool_warning(f"Error checking version: {e}") + if verbose: + io.tool_output(f"Full exception details: {traceback.format_exc()}") + return True # Safer to assume it's a first run if we hit an error + + +def check_and_load_imports(io, is_first_run, verbose=False): + try: + if is_first_run: + if verbose: + io.tool_output( + "First run for this version and executable, loading imports synchronously" + ) + try: + load_slow_imports(swallow=False) + except Exception as err: + io.tool_error(str(err)) + io.tool_output("Error loading required imports. Did you install aider properly?") + io.offer_url(urls.install_properly, "Open documentation url for more info?") + sys.exit(1) + + if verbose: + io.tool_output("Imports loaded and installs file updated") + else: + if verbose: + io.tool_output("Not first run, loading imports in background thread") + thread = threading.Thread(target=load_slow_imports) + thread.daemon = True + thread.start() + + except Exception as e: + io.tool_warning(f"Error in loading imports: {e}") + if verbose: + io.tool_output(f"Full exception details: {traceback.format_exc()}") + + +def load_slow_imports(swallow=True): # These imports are deferred in various ways to # improve startup time. - # This func is called in a thread to load them in the background - # while we wait for the user to type their first message. + # This func is called either synchronously or in a thread + # depending on whether it's been run before for this version and executable. try: import httpx # noqa: F401 import litellm # noqa: F401 import networkx # noqa: F401 import numpy # noqa: F401 - except Exception: - pass + except Exception as e: + if not swallow: + raise e if __name__ == "__main__": diff --git a/aider/models.py b/aider/models.py index 303f048d1..12e809c0f 100644 --- a/aider/models.py +++ b/aider/models.py @@ -1,23 +1,23 @@ import difflib -import importlib import json import math import os import platform import sys +import time from dataclasses import dataclass, fields from pathlib import Path from typing import Optional +import json5 import yaml from PIL import Image -from aider import urls from aider.dump import dump # noqa: F401 -from aider.llm import AIDER_APP_NAME, AIDER_SITE_URL, litellm +from aider.llm import litellm DEFAULT_MODEL_NAME = "gpt-4o" -ANTHROPIC_BETA_HEADER = "max-tokens-3-5-sonnet-2024-07-15,prompt-caching-2024-07-31" +ANTHROPIC_BETA_HEADER = "prompt-caching-2024-07-31,pdfs-2024-09-25" OPENAI_MODELS = """ gpt-4 @@ -52,13 +52,32 @@ ANTHROPIC_MODELS = """ claude-2 claude-2.1 claude-3-haiku-20240307 +claude-3-5-haiku-20241022 claude-3-opus-20240229 claude-3-sonnet-20240229 claude-3-5-sonnet-20240620 +claude-3-5-sonnet-20241022 """ ANTHROPIC_MODELS = [ln.strip() for ln in ANTHROPIC_MODELS.splitlines() if ln.strip()] +# Mapping of model aliases to their canonical names +MODEL_ALIASES = { + # Claude models + "sonnet": "claude-3-5-sonnet-20241022", + "haiku": "claude-3-5-haiku-20241022", + "opus": "claude-3-opus-20240229", + # GPT models + "4": "gpt-4-0613", + "4o": "gpt-4o-2024-08-06", + "4-turbo": "gpt-4-1106-preview", + "35turbo": "gpt-3.5-turbo", + "35-turbo": "gpt-3.5-turbo", + "3": "gpt-3.5-turbo", + # Other models + "deepseek": "deepseek/deepseek-coder", +} + @dataclass class ModelSettings: @@ -68,13 +87,17 @@ class ModelSettings: weak_model_name: Optional[str] = None use_repo_map: bool = False send_undo_reply: bool = False - accepts_images: bool = False lazy: bool = False reminder: str = "user" examples_as_sys_msg: bool = False - extra_headers: Optional[dict] = None - max_tokens: Optional[int] = None + extra_params: Optional[dict] = None cache_control: bool = False + caches_by_default: bool = False + use_system_prompt: bool = True + use_temperature: bool = True + streaming: bool = True + editor_model_name: Optional[str] = None + editor_edit_format: Optional[str] = None # https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo @@ -119,8 +142,6 @@ MODEL_SETTINGS = [ "udiff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, - accepts_images=True, lazy=True, reminder="sys", ), @@ -129,8 +150,6 @@ MODEL_SETTINGS = [ "udiff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, - accepts_images=True, lazy=True, reminder="sys", ), @@ -139,18 +158,15 @@ MODEL_SETTINGS = [ "diff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, - accepts_images=True, lazy=True, reminder="sys", + editor_edit_format="editor-diff", ), ModelSettings( "openai/gpt-4o-2024-08-06", "diff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, - accepts_images=True, lazy=True, reminder="sys", ), @@ -159,8 +175,22 @@ MODEL_SETTINGS = [ "diff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, - accepts_images=True, + lazy=True, + reminder="sys", + ), + ModelSettings( + "gpt-4o-2024-11-20", + "diff", + weak_model_name="gpt-4o-mini", + use_repo_map=True, + lazy=True, + reminder="sys", + ), + ModelSettings( + "openai/gpt-4o-2024-11-20", + "diff", + weak_model_name="gpt-4o-mini", + use_repo_map=True, lazy=True, reminder="sys", ), @@ -169,16 +199,14 @@ MODEL_SETTINGS = [ "diff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, - accepts_images=True, lazy=True, reminder="sys", + editor_edit_format="editor-diff", ), ModelSettings( "gpt-4o-mini", "whole", weak_model_name="gpt-4o-mini", - accepts_images=True, lazy=True, reminder="sys", ), @@ -186,7 +214,6 @@ MODEL_SETTINGS = [ "openai/gpt-4o-mini", "whole", weak_model_name="openai/gpt-4o-mini", - accepts_images=True, lazy=True, reminder="sys", ), @@ -195,7 +222,6 @@ MODEL_SETTINGS = [ "udiff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, lazy=True, reminder="sys", examples_as_sys_msg=True, @@ -205,7 +231,6 @@ MODEL_SETTINGS = [ "udiff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, lazy=True, reminder="sys", ), @@ -214,8 +239,6 @@ MODEL_SETTINGS = [ "diff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, - accepts_images=True, reminder="sys", ), ModelSettings( @@ -223,7 +246,6 @@ MODEL_SETTINGS = [ "diff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, reminder="sys", examples_as_sys_msg=True, ), @@ -232,7 +254,6 @@ MODEL_SETTINGS = [ "diff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, reminder="sys", ), ModelSettings( @@ -240,113 +261,264 @@ MODEL_SETTINGS = [ "diff", weak_model_name="gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, reminder="sys", ), # Claude ModelSettings( "claude-3-opus-20240229", "diff", - weak_model_name="claude-3-haiku-20240307", + weak_model_name="claude-3-5-haiku-20241022", use_repo_map=True, - send_undo_reply=True, ), ModelSettings( "openrouter/anthropic/claude-3-opus", "diff", - weak_model_name="openrouter/anthropic/claude-3-haiku", + weak_model_name="openrouter/anthropic/claude-3-5-haiku", use_repo_map=True, - send_undo_reply=True, ), ModelSettings( "claude-3-sonnet-20240229", "whole", - weak_model_name="claude-3-haiku-20240307", + weak_model_name="claude-3-5-haiku-20241022", ), ModelSettings( "claude-3-5-sonnet-20240620", "diff", - weak_model_name="claude-3-haiku-20240307", + weak_model_name="claude-3-5-haiku-20241022", + editor_model_name="claude-3-5-sonnet-20240620", + editor_edit_format="editor-diff", use_repo_map=True, examples_as_sys_msg=True, - accepts_images=True, - max_tokens=8192, - extra_headers={ - "anthropic-beta": ANTHROPIC_BETA_HEADER, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, + "max_tokens": 8192, }, cache_control=True, - reminder=None, + reminder="user", ), ModelSettings( "anthropic/claude-3-5-sonnet-20240620", "diff", - weak_model_name="claude-3-haiku-20240307", + weak_model_name="anthropic/claude-3-5-haiku-20241022", + editor_model_name="anthropic/claude-3-5-sonnet-20240620", + editor_edit_format="editor-diff", use_repo_map=True, examples_as_sys_msg=True, - max_tokens=8192, - extra_headers={ - "anthropic-beta": ANTHROPIC_BETA_HEADER, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, + "max_tokens": 8192, }, cache_control=True, - reminder=None, + reminder="user", + ), + ModelSettings( + "anthropic/claude-3-5-sonnet-20241022", + "diff", + weak_model_name="anthropic/claude-3-5-haiku-20241022", + editor_model_name="anthropic/claude-3-5-sonnet-20241022", + editor_edit_format="editor-diff", + use_repo_map=True, + examples_as_sys_msg=True, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, + "max_tokens": 8192, + }, + cache_control=True, + reminder="user", + ), + ModelSettings( + "bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0", + "diff", + weak_model_name="bedrock/anthropic.claude-3-5-haiku-20241022-v1:0", + editor_model_name="bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0", + editor_edit_format="editor-diff", + use_repo_map=True, + examples_as_sys_msg=True, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, + "max_tokens": 8192, + }, + cache_control=True, + reminder="user", + ), + ModelSettings( + "anthropic/claude-3-5-sonnet-latest", + "diff", + weak_model_name="anthropic/claude-3-5-haiku-20241022", + editor_model_name="anthropic/claude-3-5-sonnet-20241022", + editor_edit_format="editor-diff", + use_repo_map=True, + examples_as_sys_msg=True, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, + "max_tokens": 8192, + }, + cache_control=True, + reminder="user", + ), + ModelSettings( + "claude-3-5-sonnet-20241022", + "diff", + weak_model_name="claude-3-5-haiku-20241022", + editor_model_name="claude-3-5-sonnet-20241022", + editor_edit_format="editor-diff", + use_repo_map=True, + examples_as_sys_msg=True, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, + "max_tokens": 8192, + }, + cache_control=True, + reminder="user", ), ModelSettings( "anthropic/claude-3-haiku-20240307", "whole", weak_model_name="anthropic/claude-3-haiku-20240307", examples_as_sys_msg=True, - extra_headers={ - "anthropic-beta": ANTHROPIC_BETA_HEADER, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, }, cache_control=True, ), + ModelSettings( + "anthropic/claude-3-5-haiku-20241022", + "diff", + weak_model_name="anthropic/claude-3-5-haiku-20241022", + use_repo_map=True, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, + }, + cache_control=True, + ), + ModelSettings( + "bedrock/anthropic.claude-3-5-haiku-20241022-v1:0", + "diff", + weak_model_name="bedrock/anthropic.claude-3-5-haiku-20241022-v1:0", + use_repo_map=True, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, + }, + cache_control=True, + ), + ModelSettings( + "claude-3-5-haiku-20241022", + "diff", + weak_model_name="claude-3-5-haiku-20241022", + use_repo_map=True, + examples_as_sys_msg=True, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, + }, + cache_control=True, + ), + ModelSettings( + "vertex_ai/claude-3-5-haiku@20241022", + "diff", + weak_model_name="vertex_ai/claude-3-5-haiku@20241022", + use_repo_map=True, + extra_params={ + "max_tokens": 4096, + }, + ), ModelSettings( "claude-3-haiku-20240307", "whole", weak_model_name="claude-3-haiku-20240307", examples_as_sys_msg=True, - extra_headers={ - "anthropic-beta": ANTHROPIC_BETA_HEADER, + extra_params={ + "extra_headers": { + "anthropic-beta": ANTHROPIC_BETA_HEADER, + }, }, cache_control=True, ), ModelSettings( "openrouter/anthropic/claude-3.5-sonnet", "diff", - weak_model_name="openrouter/anthropic/claude-3-haiku-20240307", + weak_model_name="openrouter/anthropic/claude-3-5-haiku", + editor_model_name="openrouter/anthropic/claude-3.5-sonnet", + editor_edit_format="editor-diff", use_repo_map=True, examples_as_sys_msg=True, - accepts_images=True, - max_tokens=8192, - extra_headers={ - "anthropic-beta": "max-tokens-3-5-sonnet-2024-07-15", - "HTTP-Referer": AIDER_SITE_URL, - "X-Title": AIDER_APP_NAME, + extra_params={ + "max_tokens": 8192, }, - reminder=None, + reminder="user", + cache_control=True, + ), + ModelSettings( + "openrouter/anthropic/claude-3.5-sonnet:beta", + "diff", + weak_model_name="openrouter/anthropic/claude-3-5-haiku:beta", + editor_model_name="openrouter/anthropic/claude-3.5-sonnet:beta", + editor_edit_format="editor-diff", + use_repo_map=True, + examples_as_sys_msg=True, + extra_params={ + "max_tokens": 8192, + }, + reminder="user", + cache_control=True, ), # Vertex AI Claude models # Does not yet support 8k token ModelSettings( "vertex_ai/claude-3-5-sonnet@20240620", "diff", - weak_model_name="vertex_ai/claude-3-haiku@20240307", + weak_model_name="vertex_ai/claude-3-5-haiku@20241022", + editor_model_name="vertex_ai/claude-3-5-sonnet@20240620", + editor_edit_format="editor-diff", use_repo_map=True, examples_as_sys_msg=True, - accepts_images=True, - reminder=None, + extra_params={ + "max_tokens": 8192, + }, + reminder="user", + ), + ModelSettings( + "vertex_ai/claude-3-5-sonnet-v2@20241022", + "diff", + weak_model_name="vertex_ai/claude-3-5-haiku@20241022", + editor_model_name="vertex_ai/claude-3-5-sonnet-v2@20241022", + editor_edit_format="editor-diff", + use_repo_map=True, + examples_as_sys_msg=True, + extra_params={ + "max_tokens": 8192, + }, + reminder="user", ), ModelSettings( "vertex_ai/claude-3-opus@20240229", "diff", - weak_model_name="vertex_ai/claude-3-haiku@20240307", + weak_model_name="vertex_ai/claude-3-5-haiku@20241022", use_repo_map=True, - send_undo_reply=True, ), ModelSettings( "vertex_ai/claude-3-sonnet@20240229", "whole", - weak_model_name="vertex_ai/claude-3-haiku@20240307", + weak_model_name="vertex_ai/claude-3-5-haiku@20241022", ), # Cohere ModelSettings( @@ -354,7 +526,19 @@ MODEL_SETTINGS = [ "whole", weak_model_name="command-r-plus", use_repo_map=True, - send_undo_reply=True, + ), + # New Cohere models + ModelSettings( + "command-r-08-2024", + "whole", + weak_model_name="command-r-08-2024", + use_repo_map=True, + ), + ModelSettings( + "command-r-plus-08-2024", + "whole", + weak_model_name="command-r-plus-08-2024", + use_repo_map=True, ), # Groq llama3 ModelSettings( @@ -375,39 +559,87 @@ MODEL_SETTINGS = [ examples_as_sys_msg=True, ), # Gemini + ModelSettings( + "gemini/gemini-1.5-pro-002", + "diff", + use_repo_map=True, + ), + ModelSettings( + "gemini/gemini-1.5-flash-002", + "whole", + ), ModelSettings( "gemini/gemini-1.5-pro", "diff-fenced", use_repo_map=True, - send_undo_reply=True, ), ModelSettings( "gemini/gemini-1.5-pro-latest", "diff-fenced", use_repo_map=True, - send_undo_reply=True, + ), + ModelSettings( + "gemini/gemini-1.5-pro-exp-0827", + "diff-fenced", + use_repo_map=True, + ), + ModelSettings( + "vertex_ai/gemini-pro-experimental", + "diff-fenced", + use_repo_map=True, + ), + ModelSettings( + "gemini/gemini-1.5-flash-exp-0827", + "whole", + use_repo_map=False, + send_undo_reply=False, ), ModelSettings( "deepseek/deepseek-chat", "diff", use_repo_map=True, - send_undo_reply=True, examples_as_sys_msg=True, reminder="sys", + extra_params={ + "max_tokens": 8192, + }, ), ModelSettings( "deepseek/deepseek-coder", "diff", use_repo_map=True, - send_undo_reply=True, examples_as_sys_msg=True, reminder="sys", + caches_by_default=True, + extra_params={ + "max_tokens": 8192, + }, + ), + ModelSettings( + "deepseek-chat", + "diff", + use_repo_map=True, + examples_as_sys_msg=True, + reminder="sys", + extra_params={ + "max_tokens": 8192, + }, + ), + ModelSettings( + "deepseek-coder", + "diff", + use_repo_map=True, + examples_as_sys_msg=True, + reminder="sys", + caches_by_default=True, + extra_params={ + "max_tokens": 8192, + }, ), ModelSettings( "openrouter/deepseek/deepseek-coder", "diff", use_repo_map=True, - send_undo_reply=True, examples_as_sys_msg=True, reminder="sys", ), @@ -416,24 +648,207 @@ MODEL_SETTINGS = [ "diff", weak_model_name="openrouter/openai/gpt-4o-mini", use_repo_map=True, - send_undo_reply=True, - accepts_images=True, lazy=True, reminder="sys", + editor_edit_format="editor-diff", + ), + ModelSettings( + "openai/o1-mini", + "whole", + weak_model_name="openai/gpt-4o-mini", + editor_model_name="openai/gpt-4o", + editor_edit_format="editor-diff", + use_repo_map=True, + reminder="user", + use_system_prompt=False, + use_temperature=False, + ), + ModelSettings( + "azure/o1-mini", + "whole", + weak_model_name="azure/gpt-4o-mini", + editor_model_name="azure/gpt-4o", + editor_edit_format="editor-diff", + use_repo_map=True, + reminder="user", + use_system_prompt=False, + use_temperature=False, + ), + ModelSettings( + "o1-mini", + "whole", + weak_model_name="gpt-4o-mini", + editor_model_name="gpt-4o", + editor_edit_format="editor-diff", + use_repo_map=True, + reminder="user", + use_system_prompt=False, + use_temperature=False, + ), + ModelSettings( + "openai/o1-preview", + "diff", + weak_model_name="openai/gpt-4o-mini", + editor_model_name="openai/gpt-4o", + editor_edit_format="editor-diff", + use_repo_map=True, + reminder="user", + use_system_prompt=False, + use_temperature=False, + ), + ModelSettings( + "azure/o1-preview", + "diff", + weak_model_name="azure/gpt-4o-mini", + editor_model_name="azure/gpt-4o", + editor_edit_format="editor-diff", + use_repo_map=True, + reminder="user", + use_system_prompt=False, + use_temperature=False, + ), + ModelSettings( + "o1-preview", + "architect", + weak_model_name="gpt-4o-mini", + editor_model_name="gpt-4o", + editor_edit_format="editor-diff", + use_repo_map=True, + reminder="user", + use_system_prompt=False, + use_temperature=False, + ), + ModelSettings( + "openrouter/openai/o1-mini", + "whole", + weak_model_name="openrouter/openai/gpt-4o-mini", + editor_model_name="openrouter/openai/gpt-4o", + editor_edit_format="editor-diff", + use_repo_map=True, + reminder="user", + use_system_prompt=False, + use_temperature=False, + streaming=False, + ), + ModelSettings( + "openrouter/openai/o1-preview", + "diff", + weak_model_name="openrouter/openai/gpt-4o-mini", + editor_model_name="openrouter/openai/gpt-4o", + editor_edit_format="editor-diff", + use_repo_map=True, + reminder="user", + use_system_prompt=False, + use_temperature=False, + streaming=False, + ), + ModelSettings( + "openrouter/qwen/qwen-2.5-coder-32b-instruct", + "diff", + weak_model_name="openrouter/qwen/qwen-2.5-coder-32b-instruct", + editor_model_name="openrouter/qwen/qwen-2.5-coder-32b-instruct", + editor_edit_format="editor-diff", + use_repo_map=True, ), ] -class Model: - def __init__(self, model, weak_model=None): - # Set defaults from ModelSettings - default_settings = ModelSettings(name="") - for field in fields(ModelSettings): - setattr(self, field.name, getattr(default_settings, field.name)) +class ModelInfoManager: + MODEL_INFO_URL = ( + "https://raw.githubusercontent.com/BerriAI/litellm/main/" + "model_prices_and_context_window.json" + ) + CACHE_TTL = 60 * 60 * 24 # 24 hours + + def __init__(self): + self.cache_dir = Path.home() / ".aider" / "caches" + self.cache_file = self.cache_dir / "model_prices_and_context_window.json" + self.content = None + self._load_cache() + + def _load_cache(self): + try: + self.cache_dir.mkdir(parents=True, exist_ok=True) + if self.cache_file.exists(): + cache_age = time.time() - self.cache_file.stat().st_mtime + if cache_age < self.CACHE_TTL: + self.content = json.loads(self.cache_file.read_text()) + except OSError: + pass + + def _update_cache(self): + try: + import requests + + response = requests.get(self.MODEL_INFO_URL, timeout=5) + if response.status_code == 200: + self.content = response.json() + try: + self.cache_file.write_text(json.dumps(self.content, indent=4)) + except OSError: + pass + except Exception as ex: + print(str(ex)) + try: + # Save empty dict to cache file on failure + self.cache_file.write_text("{}") + except OSError: + pass + + def get_model_from_cached_json_db(self, model): + if not self.content: + self._update_cache() + + if not self.content: + return dict() + + info = self.content.get(model, dict()) + if info: + return info + + pieces = model.split("/") + if len(pieces) == 2: + info = self.content.get(pieces[1]) + if info and info.get("litellm_provider") == pieces[0]: + return info + + return dict() + + def get_model_info(self, model): + cached_info = self.get_model_from_cached_json_db(model) + + litellm_info = None + if litellm._lazy_module or not cached_info: + try: + litellm_info = litellm.get_model_info(model) + except Exception as ex: + if "model_prices_and_context_window.json" not in str(ex): + print(str(ex)) + + if litellm_info: + return litellm_info + + return cached_info + + +model_info_manager = ModelInfoManager() + + +class Model(ModelSettings): + def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None): + # Map any alias to its canonical name + model = MODEL_ALIASES.get(model, model) self.name = model + self.max_chat_history_tokens = 1024 self.weak_model = None + self.editor_model = None + + # Find the extra settings + self.extra_model_settings = next( + (ms for ms in MODEL_SETTINGS if ms.name == "aider/extra_params"), None + ) self.info = self.get_model_info(model) @@ -454,36 +869,52 @@ class Model: else: self.get_weak_model(weak_model) - def get_model_info(self, model): - if not litellm._lazy_module: - # Try and do this quickly, without triggering the litellm import - spec = importlib.util.find_spec("litellm") - if spec: - origin = Path(spec.origin) - fname = origin.parent / "model_prices_and_context_window_backup.json" - if fname.exists(): - data = json.loads(fname.read_text()) - info = data.get(model) - if info: - return info + if editor_model is False: + self.editor_model_name = None + else: + self.get_editor_model(editor_model, editor_edit_format) - # Do it the slow way... - try: - return litellm.get_model_info(model) - except Exception: - return dict() + def get_model_info(self, model): + return model_info_manager.get_model_info(model) + + def _copy_fields(self, source): + """Helper to copy fields from a ModelSettings instance to self""" + for field in fields(ModelSettings): + val = getattr(source, field.name) + setattr(self, field.name, val) def configure_model_settings(self, model): + # Look for exact model match + exact_match = False for ms in MODEL_SETTINGS: # direct match, or match "provider/" if model == ms.name: - for field in fields(ModelSettings): - val = getattr(ms, field.name) - setattr(self, field.name, val) - return # <-- + self._copy_fields(ms) + exact_match = True + break # Continue to apply overrides model = model.lower() + # If no exact match, try generic settings + if not exact_match: + self.apply_generic_model_settings(model) + + # Apply override settings last if they exist + if self.extra_model_settings and self.extra_model_settings.extra_params: + # Initialize extra_params if it doesn't exist + if not self.extra_params: + self.extra_params = {} + + # Deep merge the extra_params dicts + for key, value in self.extra_model_settings.extra_params.items(): + if isinstance(value, dict) and isinstance(self.extra_params.get(key), dict): + # For nested dicts, merge recursively + self.extra_params[key] = {**self.extra_params[key], **value} + else: + # For non-dict values, simply update + self.extra_params[key] = value + + def apply_generic_model_settings(self, model): if ("llama3" in model or "llama-3" in model) and "70b" in model: self.edit_format = "diff" self.use_repo_map = True @@ -505,16 +936,37 @@ class Model: if "gpt-3.5" in model or "gpt-4" in model: self.reminder = "sys" + return # <-- if "3.5-sonnet" in model or "3-5-sonnet" in model: self.edit_format = "diff" self.use_repo_map = True self.examples_as_sys_msg = True - self.reminder = None + self.reminder = "user" + return # <-- + + if model.startswith("o1-") or "/o1-" in model: + self.use_system_prompt = False + self.use_temperature = False + return # <-- + + if ( + "qwen" in model + and "coder" in model + and ("2.5" in model or "2-5" in model) + and "32b" in model + ): + self.edit_format = "diff" + self.editor_edit_format = "editor-diff" + self.use_repo_map = True + if model.startswith("ollama/") or model.startswith("ollama_chat/"): + self.extra_params = dict(num_ctx=8 * 1024) + return # <-- # use the defaults if self.edit_format == "diff": self.use_repo_map = True + return # <-- def __str__(self): return self.name @@ -541,6 +993,26 @@ class Model: def commit_message_models(self): return [self.weak_model, self] + def get_editor_model(self, provided_editor_model_name, editor_edit_format): + # If editor_model_name is provided, override the model settings + if provided_editor_model_name: + self.editor_model_name = provided_editor_model_name + if editor_edit_format: + self.editor_edit_format = editor_edit_format + + if not self.editor_model_name or self.editor_model_name == self.name: + self.editor_model = self + else: + self.editor_model = Model( + self.editor_model_name, + editor_model=False, + ) + + if not self.editor_edit_format: + self.editor_edit_format = self.editor_model.edit_format + + return self.editor_model + def tokenizer(self, text): return litellm.encode(model=self.name, text=text) @@ -560,7 +1032,11 @@ class Model: else: msgs = json.dumps(messages) - return len(self.tokenizer(msgs)) + try: + return len(self.tokenizer(msgs)) + except Exception as err: + print(f"Unable to count tokens: {err}") + return 0 def token_count_for_image(self, fname): """ @@ -647,6 +1123,9 @@ def register_models(model_settings_fnames): if not os.path.exists(model_settings_fname): continue + if not Path(model_settings_fname).read_text().strip(): + continue + try: with open(model_settings_fname, "r") as model_settings_file: model_settings_list = yaml.safe_load(model_settings_file) @@ -674,8 +1153,14 @@ def register_litellm_models(model_fnames): continue try: - with open(model_fname, "r") as model_def_file: - model_def = json.load(model_def_file) + data = Path(model_fname).read_text() + if not data.strip(): + continue + model_def = json5.loads(data) + if not model_def: + continue + + # only load litellm if we have actual data litellm._load_litellm() litellm.register_model(model_def) except Exception as e: @@ -697,9 +1182,21 @@ def validate_variables(vars): def sanity_check_models(io, main_model): - sanity_check_model(io, main_model) + problem_main = sanity_check_model(io, main_model) + + problem_weak = None if main_model.weak_model and main_model.weak_model is not main_model: - sanity_check_model(io, main_model.weak_model) + problem_weak = sanity_check_model(io, main_model.weak_model) + + problem_editor = None + if ( + main_model.editor_model + and main_model.editor_model is not main_model + and main_model.editor_model is not main_model.weak_model + ): + problem_editor = sanity_check_model(io, main_model.editor_model) + + return problem_main or problem_weak or problem_editor def sanity_check_model(io, model): @@ -707,9 +1204,11 @@ def sanity_check_model(io, model): if model.missing_keys: show = True - io.tool_error(f"Model {model}: Missing these environment variables:") + io.tool_warning(f"Warning: {model} expects these environment variables") for key in model.missing_keys: - io.tool_error(f"- {key}") + value = os.environ.get(key, "") + status = "Set" if value else "Not set" + io.tool_output(f"- {key}: {status}") if platform.system() == "Windows" or True: io.tool_output( @@ -719,12 +1218,12 @@ def sanity_check_model(io, model): elif not model.keys_in_environment: show = True - io.tool_output(f"Model {model}: Unknown which environment variables are required.") + io.tool_warning(f"Warning for {model}: Unknown which environment variables are required.") if not model.info: show = True - io.tool_output( - f"Model {model}: Unknown context window size and costs, using sane defaults." + io.tool_warning( + f"Warning for {model}: Unknown context window size and costs, using sane defaults." ) possible_matches = fuzzy_match_models(model.name) @@ -733,8 +1232,7 @@ def sanity_check_model(io, model): for match in possible_matches: io.tool_output(f"- {match}") - if show: - io.tool_output(f"For more info, see: {urls.model_warnings}\n") + return show def fuzzy_match_models(name): @@ -745,7 +1243,10 @@ def fuzzy_match_models(name): model = model.lower() if attrs.get("mode") != "chat": continue - provider = (attrs["litellm_provider"] + "/").lower() + provider = attrs.get("litellm_provider", "").lower() + if not provider: + continue + provider += "/" if model.startswith(provider): fq_model = model @@ -786,20 +1287,37 @@ def print_matching_models(io, search): io.tool_output(f'No models match "{search}".') +def get_model_settings_as_yaml(): + import yaml + + model_settings_list = [] + for ms in MODEL_SETTINGS: + model_settings_dict = { + field.name: getattr(ms, field.name) for field in fields(ModelSettings) + } + model_settings_list.append(model_settings_dict) + + return yaml.dump(model_settings_list, default_flow_style=False) + + def main(): - if len(sys.argv) != 2: - print("Usage: python models.py ") + if len(sys.argv) < 2: + print("Usage: python models.py or python models.py --yaml") sys.exit(1) - model_name = sys.argv[1] - matching_models = fuzzy_match_models(model_name) - - if matching_models: - print(f"Matching models for '{model_name}':") - for model in matching_models: - print(model) + if sys.argv[1] == "--yaml": + yaml_string = get_model_settings_as_yaml() + print(yaml_string) else: - print(f"No matching models found for '{model_name}'.") + model_name = sys.argv[1] + matching_models = fuzzy_match_models(model_name) + + if matching_models: + print(f"Matching models for '{model_name}':") + for model in matching_models: + print(model) + else: + print(f"No matching models found for '{model_name}'.") if __name__ == "__main__": diff --git a/aider/prompts.py b/aider/prompts.py index 4fc2f008f..27d833fdd 100644 --- a/aider/prompts.py +++ b/aider/prompts.py @@ -5,14 +5,21 @@ # Conventional Commits text adapted from: # https://www.conventionalcommits.org/en/v1.0.0/#summary -commit_system = """You are an expert software engineer. +commit_system = """You are an expert software engineer that generates concise, \ +one-line Git commit messages based on the provided diffs. Review the provided context and diffs which are about to be committed to a git repo. Review the diffs carefully. -Generate a commit message for those changes. -The commit message MUST use the imperative tense. +Generate a one-line commit message for those changes. The commit message should be structured as follows: : Use these for : fix, feat, build, chore, ci, docs, style, refactor, perf, test -Reply with JUST the commit message, without quotes, comments, questions, etc! + +Ensure the commit message: +- Starts with the appropriate prefix. +- Is in the imperative mood (e.g., \"Add feature\" not \"Added feature\" or \"Adding feature\"). +- Does not exceed 72 characters. + +Reply only with the one-line commit message, without any additional text, explanations, \ +or line breaks. """ # COMMANDS diff --git a/aider/queries/tree-sitter-dart-tags.scm b/aider/queries/tree-sitter-dart-tags.scm new file mode 100644 index 000000000..1aacad0de --- /dev/null +++ b/aider/queries/tree-sitter-dart-tags.scm @@ -0,0 +1,91 @@ +(class_definition + name: (identifier) @name.definition.class) @definition.class + +(method_signature + (function_signature)) @definition.method + +(type_alias + (type_identifier) @name.definition.type) @definition.type + +(method_signature + (getter_signature + name: (identifier) @name.definition.method)) @definition.method + +(method_signature + (setter_signature + name: (identifier) @name.definition.method)) @definition.method + +(method_signature + (function_signature + name: (identifier) @name.definition.method)) @definition.method + +(method_signature + (factory_constructor_signature + (identifier) @name.definition.method)) @definition.method + +(method_signature + (constructor_signature + name: (identifier) @name.definition.method)) @definition.method + +(method_signature + (operator_signature)) @definition.method + +(method_signature) @definition.method + +(mixin_declaration + (mixin) + (identifier) @name.definition.mixin) @definition.mixin + +(extension_declaration + name: (identifier) @name.definition.extension) @definition.extension + +(enum_declaration + name: (identifier) @name.definition.enum) @definition.enum + +(function_signature + name: (identifier) @name.definition.function) @definition.function + +(new_expression + (type_identifier) @name.reference.class) @reference.class + +(initialized_variable_definition + name: (identifier) + value: (identifier) @name.reference.class + value: (selector + "!"? + (argument_part + (arguments + (argument)*))?)?) @reference.class + +(assignment_expression + left: (assignable_expression + (identifier) + (unconditional_assignable_selector + "." + (identifier) @name.reference.call))) @reference.call + +(assignment_expression + left: (assignable_expression + (identifier) + (conditional_assignable_selector + "?." + (identifier) @name.reference.call))) @reference.call + +((identifier) @name + (selector + "!"? + (conditional_assignable_selector + "?." (identifier) @name.reference.call)? + (unconditional_assignable_selector + "."? (identifier) @name.reference.call)? + (argument_part + (arguments + (argument)*))?)* + (cascade_section + (cascade_selector + (identifier)) @name.reference.call + (argument_part + (arguments + (argument)*))?)?) @reference.call + + diff --git a/aider/repo.py b/aider/repo.py index 8122df748..3445a1848 100644 --- a/aider/repo.py +++ b/aider/repo.py @@ -10,6 +10,16 @@ from aider.sendchat import simple_send_with_retries from .dump import dump # noqa: F401 +ANY_GIT_ERROR = ( + git.exc.ODBError, + git.exc.GitError, + OSError, + IndexError, + BufferError, + TypeError, + ValueError, +) + class GitRepo: repo = None @@ -19,6 +29,7 @@ class GitRepo: aider_ignore_last_check = 0 subtree_only = False ignore_file_cache = {} + git_repo_error = None def __init__( self, @@ -67,9 +78,7 @@ class GitRepo: repo_path = git.Repo(fname, search_parent_directories=True).working_dir repo_path = utils.safe_abs_path(repo_path) repo_paths.append(repo_path) - except git.exc.InvalidGitRepositoryError: - pass - except git.exc.NoSuchPathError: + except ANY_GIT_ERROR: pass num_repos = len(set(repo_paths)) @@ -116,7 +125,10 @@ class GitRepo: if fnames: fnames = [str(self.abs_root_path(fn)) for fn in fnames] for fname in fnames: - self.repo.git.add(fname) + try: + self.repo.git.add(fname) + except ANY_GIT_ERROR as err: + self.io.tool_error(f"Unable to add {fname}: {err}") cmd += ["--"] + fnames else: cmd += ["-a"] @@ -132,30 +144,32 @@ class GitRepo: original_auther_name_env = os.environ.get("GIT_AUTHOR_NAME") os.environ["GIT_AUTHOR_NAME"] = committer_name - self.repo.git.commit(cmd) - commit_hash = self.repo.head.commit.hexsha[:7] - self.io.tool_output(f"Commit {commit_hash} {commit_message}", bold=True) + try: + self.repo.git.commit(cmd) + commit_hash = self.get_head_commit_sha(short=True) + self.io.tool_output(f"Commit {commit_hash} {commit_message}", bold=True) + return commit_hash, commit_message + except ANY_GIT_ERROR as err: + self.io.tool_error(f"Unable to commit: {err}") + finally: + # Restore the env - # Restore the env + if self.attribute_committer: + if original_committer_name_env is not None: + os.environ["GIT_COMMITTER_NAME"] = original_committer_name_env + else: + del os.environ["GIT_COMMITTER_NAME"] - if self.attribute_committer: - if original_committer_name_env is not None: - os.environ["GIT_COMMITTER_NAME"] = original_committer_name_env - else: - del os.environ["GIT_COMMITTER_NAME"] - - if aider_edits and self.attribute_author: - if original_auther_name_env is not None: - os.environ["GIT_AUTHOR_NAME"] = original_auther_name_env - else: - del os.environ["GIT_AUTHOR_NAME"] - - return commit_hash, commit_message + if aider_edits and self.attribute_author: + if original_auther_name_env is not None: + os.environ["GIT_AUTHOR_NAME"] = original_auther_name_env + else: + del os.environ["GIT_AUTHOR_NAME"] def get_rel_repo_dir(self): try: return os.path.relpath(self.repo.git_dir, os.getcwd()) - except ValueError: + except (ValueError, OSError): return self.repo.git_dir def get_commit_message(self, diffs, context): @@ -178,7 +192,9 @@ class GitRepo: max_tokens = model.info.get("max_input_tokens") or 0 if max_tokens and num_tokens > max_tokens: continue - commit_message = simple_send_with_retries(model.name, messages) + commit_message = simple_send_with_retries( + model.name, messages, extra_params=model.extra_params + ) if commit_message: break @@ -201,9 +217,9 @@ class GitRepo: try: commits = self.repo.iter_commits(active_branch) current_branch_has_commits = any(commits) - except git.exc.GitCommandError: + except ANY_GIT_ERROR: pass - except TypeError: + except (TypeError,) + ANY_GIT_ERROR: pass if not fnames: @@ -214,18 +230,21 @@ class GitRepo: if not self.path_in_repo(fname): diffs += f"Added {fname}\n" - if current_branch_has_commits: - args = ["HEAD", "--"] + list(fnames) - diffs += self.repo.git.diff(*args) + try: + if current_branch_has_commits: + args = ["HEAD", "--"] + list(fnames) + diffs += self.repo.git.diff(*args) + return diffs + + wd_args = ["--"] + list(fnames) + index_args = ["--cached"] + wd_args + + diffs += self.repo.git.diff(*index_args) + diffs += self.repo.git.diff(*wd_args) + return diffs - - wd_args = ["--"] + list(fnames) - index_args = ["--cached"] + wd_args - - diffs += self.repo.git.diff(*index_args) - diffs += self.repo.git.diff(*wd_args) - - return diffs + except ANY_GIT_ERROR as err: + self.io.tool_error(f"Unable to diff: {err}") def diff_commits(self, pretty, from_commit, to_commit): args = [] @@ -247,15 +266,26 @@ class GitRepo: commit = self.repo.head.commit except ValueError: commit = None + except ANY_GIT_ERROR as err: + self.git_repo_error = err + self.io.tool_error(f"Unable to list files in git repo: {err}") + self.io.tool_output("Is your git repo corrupted?") + return [] files = set() if commit: if commit in self.tree_files: files = self.tree_files[commit] else: - for blob in commit.tree.traverse(): - if blob.type == "blob": # blob is a file - files.add(blob.path) + try: + for blob in commit.tree.traverse(): + if blob.type == "blob": # blob is a file + files.add(blob.path) + except ANY_GIT_ERROR as err: + self.git_repo_error = err + self.io.tool_error(f"Unable to list files in git repo: {err}") + self.io.tool_output("Is your git repo corrupted?") + return [] files = set(self.normalize_path(path) for path in files) self.tree_files[commit] = set(files) @@ -301,6 +331,15 @@ class GitRepo: lines, ) + def git_ignored_file(self, path): + if not self.repo: + return + try: + if self.repo.ignored(path): + return True + except ANY_GIT_ERROR: + return False + def ignored_file(self, fname): self.refresh_aider_ignore() @@ -314,7 +353,14 @@ class GitRepo: def ignored_file_raw(self, fname): if self.subtree_only: fname_path = Path(self.normalize_path(fname)) - cwd_path = Path.cwd().resolve().relative_to(Path(self.root).resolve()) + try: + cwd_path = Path.cwd().resolve().relative_to(Path(self.root).resolve()) + except ValueError: + # Issue #1524 + # ValueError: 'C:\\dev\\squid-certbot' is not in the subpath of + # 'C:\\dev\\squid-certbot' + # Clearly, fname is not under cwd... so ignore it + return True if cwd_path not in fname_path.parents and fname_path != cwd_path: return True @@ -332,6 +378,8 @@ class GitRepo: def path_in_repo(self, path): if not self.repo: return + if not path: + return tracked_files = set(self.get_tracked_files()) return self.normalize_path(path) in tracked_files @@ -363,8 +411,22 @@ class GitRepo: return self.repo.is_dirty(path=path) - def get_head(self): + def get_head_commit(self): try: - return self.repo.head.commit.hexsha - except ValueError: + return self.repo.head.commit + except (ValueError,) + ANY_GIT_ERROR: return None + + def get_head_commit_sha(self, short=False): + commit = self.get_head_commit() + if not commit: + return + if short: + return commit.hexsha[:7] + return commit.hexsha + + def get_head_commit_message(self, default=None): + commit = self.get_head_commit() + if not commit: + return default + return commit.message diff --git a/aider/repomap.py b/aider/repomap.py index 1751d677b..5c9707565 100644 --- a/aider/repomap.py +++ b/aider/repomap.py @@ -2,6 +2,8 @@ import colorsys import math import os import random +import shutil +import sqlite3 import sys import time import warnings @@ -13,10 +15,10 @@ from diskcache import Cache from grep_ast import TreeContext, filename_to_lang from pygments.lexers import guess_lexer_for_filename from pygments.token import Token -from pygments.util import ClassNotFound from tqdm import tqdm from aider.dump import dump +from aider.special import filter_important_files from aider.utils import Spinner # tree_sitter is throwing a FutureWarning @@ -26,6 +28,9 @@ from tree_sitter_language_pack import get_language, get_parser # noqa: E402 Tag = namedtuple("Tag", "rel_fname fname line name kind".split()) +SQLITE_ERRORS = (sqlite3.OperationalError, sqlite3.DatabaseError, OSError) + + class RepoMap: CACHE_VERSION = 3 TAGS_CACHE_DIR = f".aider.tags.cache.v{CACHE_VERSION}" @@ -155,17 +160,59 @@ class RepoMap: return repo_content def get_rel_fname(self, fname): - return os.path.relpath(fname, self.root) + try: + return os.path.relpath(fname, self.root) + except ValueError: + # Issue #1288: ValueError: path is on mount 'C:', start on mount 'D:' + # Just return the full fname. + return fname - def split_path(self, path): - path = os.path.relpath(path, self.root) - return [path + ":"] + def tags_cache_error(self, original_error=None): + """Handle SQLite errors by trying to recreate cache, falling back to dict if needed""" + + if self.verbose and original_error: + self.io.tool_warning(f"Tags cache error: {str(original_error)}") + + if isinstance(getattr(self, "TAGS_CACHE", None), dict): + return + + path = Path(self.root) / self.TAGS_CACHE_DIR + + # Try to recreate the cache + try: + # Delete existing cache dir + if path.exists(): + shutil.rmtree(path) + + # Try to create new cache + new_cache = Cache(path) + + # Test that it works + test_key = "test" + new_cache[test_key] = "test" + _ = new_cache[test_key] + del new_cache[test_key] + + # If we got here, the new cache works + self.TAGS_CACHE = new_cache + return + + except SQLITE_ERRORS as e: + # If anything goes wrong, warn and fall back to dict + self.io.tool_warning( + f"Unable to use tags cache at {path}, falling back to memory cache" + ) + if self.verbose: + self.io.tool_warning(f"Cache recreation error: {str(e)}") + + self.TAGS_CACHE = dict() def load_tags_cache(self): path = Path(self.root) / self.TAGS_CACHE_DIR - if not path.exists(): - self.cache_missing = True - self.TAGS_CACHE = Cache(path) + try: + self.TAGS_CACHE = Cache(path) + except SQLITE_ERRORS as e: + self.tags_cache_error(e) def save_tags_cache(self): pass @@ -174,7 +221,7 @@ class RepoMap: try: return os.path.getmtime(fname) except FileNotFoundError: - self.io.tool_error(f"File not found error: {fname}") + self.io.tool_warning(f"File not found error: {fname}") def get_tags(self, fname, rel_fname): # Check if the file is in the cache and if the modification time has not changed @@ -183,15 +230,30 @@ class RepoMap: return [] cache_key = fname - if cache_key in self.TAGS_CACHE and self.TAGS_CACHE[cache_key]["mtime"] == file_mtime: - return self.TAGS_CACHE[cache_key]["data"] + try: + val = self.TAGS_CACHE.get(cache_key) # Issue #1308 + except SQLITE_ERRORS as e: + self.tags_cache_error(e) + val = self.TAGS_CACHE.get(cache_key) + + if val is not None and val.get("mtime") == file_mtime: + try: + return self.TAGS_CACHE[cache_key]["data"] + except SQLITE_ERRORS as e: + self.tags_cache_error(e) + return self.TAGS_CACHE[cache_key]["data"] # miss! data = list(self.get_tags_raw(fname, rel_fname)) # Update the cache - self.TAGS_CACHE[cache_key] = {"mtime": file_mtime, "data": data} - self.save_tags_cache() + try: + self.TAGS_CACHE[cache_key] = {"mtime": file_mtime, "data": data} + self.save_tags_cache() + except SQLITE_ERRORS as e: + self.tags_cache_error(e) + self.TAGS_CACHE[cache_key] = {"mtime": file_mtime, "data": data} + return data def get_tags_raw(self, fname, rel_fname): @@ -199,8 +261,12 @@ class RepoMap: if not lang: return - language = get_language(lang) - parser = get_parser(lang) + try: + language = get_language(lang) + parser = get_parser(lang) + except Exception as err: + print(f"Skipping file {fname}: {err}") + return query_scm = get_scm_fname(lang) if not query_scm.exists(): @@ -253,7 +319,8 @@ class RepoMap: try: lexer = guess_lexer_for_filename(fname, code) - except ClassNotFound: + except Exception: # On Windows, bad ref to time.clock which is deprecated? + # self.io.tool_error(f"Error lexing {fname}") return tokens = list(lexer.get_tokens(code)) @@ -288,7 +355,13 @@ class RepoMap: # https://networkx.org/documentation/stable/_modules/networkx/algorithms/link_analysis/pagerank_alg.html#pagerank personalize = 100 / len(fnames) - if len(fnames) - len(self.TAGS_CACHE) > 100: + try: + cache_size = len(self.TAGS_CACHE) + except SQLITE_ERRORS as e: + self.tags_cache_error(e) + cache_size = len(self.TAGS_CACHE) + + if len(fnames) - cache_size > 100: self.io.tool_output( "Initial repo scan can be slow in larger repos, but only happens once." ) @@ -298,19 +371,23 @@ class RepoMap: showing_bar = False for fname in fnames: + if self.verbose: + self.io.tool_output(f"Processing {fname}") if progress and not showing_bar: progress() - if not Path(fname).is_file(): - if fname not in self.warned_files: - if Path(fname).exists(): - self.io.tool_error( - f"Repo-map can't include {fname}, it is not a normal file" - ) - else: - self.io.tool_error(f"Repo-map can't include {fname}, it no longer exists") + try: + file_ok = Path(fname).is_file() + except OSError: + file_ok = False - self.warned_files.add(fname) + if not file_ok: + if fname not in self.warned_files: + self.io.tool_warning(f"Repo-map can't include {fname}") + self.io.tool_output( + "Has it been deleted from the file system but not from git?" + ) + self.warned_files.add(fname) continue # dump(fname) @@ -382,7 +459,11 @@ class RepoMap: try: ranked = nx.pagerank(G, weight="weight", **pers_args) except ZeroDivisionError: - return [] + # Issue #1536 + try: + ranked = nx.pagerank(G, weight="weight") + except ZeroDivisionError: + return [] # distribute the rank from each source node, across all of its out edges ranked_definitions = defaultdict(float) @@ -399,7 +480,9 @@ class RepoMap: ranked_definitions[(dst, ident)] += data["rank"] ranked_tags = [] - ranked_definitions = sorted(ranked_definitions.items(), reverse=True, key=lambda x: x[1]) + ranked_definitions = sorted( + ranked_definitions.items(), reverse=True, key=lambda x: (x[1], x[0]) + ) # dump(ranked_definitions) @@ -435,12 +518,20 @@ class RepoMap: force_refresh=False, ): # Create a cache key - cache_key = ( + cache_key = [ tuple(sorted(chat_fnames)) if chat_fnames else None, tuple(sorted(other_fnames)) if other_fnames else None, max_map_tokens, - ) + ] + if self.refresh == "auto": + cache_key += [ + tuple(sorted(mentioned_fnames)) if mentioned_fnames else None, + tuple(sorted(mentioned_idents)) if mentioned_idents else None, + ] + cache_key = tuple(cache_key) + + use_cache = False if not force_refresh: if self.refresh == "manual" and self.last_map: return self.last_map @@ -497,6 +588,14 @@ class RepoMap: progress=spin.step, ) + other_rel_fnames = sorted(set(self.get_rel_fname(fname) for fname in other_fnames)) + special_fnames = filter_important_files(other_rel_fnames) + ranked_tags_fnames = set(tag[0] for tag in ranked_tags) + special_fnames = [fn for fn in special_fnames if fn not in ranked_tags_fnames] + special_fnames = [(fn,) for fn in special_fnames] + + ranked_tags = special_fnames + ranked_tags + spin.step() num_tags = len(ranked_tags) diff --git a/aider/report.py b/aider/report.py new file mode 100644 index 000000000..0f5f613ef --- /dev/null +++ b/aider/report.py @@ -0,0 +1,200 @@ +import os +import platform +import subprocess +import sys +import traceback +import urllib.parse +import webbrowser + +from aider import __version__ +from aider.urls import github_issues +from aider.versioncheck import VERSION_CHECK_FNAME + +FENCE = "`" * 3 + + +def get_python_info(): + implementation = platform.python_implementation() + is_venv = sys.prefix != sys.base_prefix + return ( + f"Python implementation: {implementation}\nVirtual environment:" + f" {'Yes' if is_venv else 'No'}" + ) + + +def get_os_info(): + return f"OS: {platform.system()} {platform.release()} ({platform.architecture()[0]})" + + +def get_git_info(): + try: + git_version = subprocess.check_output(["git", "--version"]).decode().strip() + return f"Git version: {git_version}" + except Exception: + return "Git information unavailable" + + +def report_github_issue(issue_text, title=None, confirm=True): + """ + Compose a URL to open a new GitHub issue with the given text prefilled, + and attempt to launch it in the default web browser. + + :param issue_text: The text of the issue to file + :param title: The title of the issue (optional) + :param confirm: Whether to ask for confirmation before opening the browser (default: True) + :return: None + """ + version_info = f"Aider version: {__version__}\n" + python_version = f"Python version: {sys.version.split()[0]}\n" + platform_info = f"Platform: {platform.platform()}\n" + python_info = get_python_info() + "\n" + os_info = get_os_info() + "\n" + git_info = get_git_info() + "\n" + + system_info = ( + version_info + python_version + platform_info + python_info + os_info + git_info + "\n" + ) + + issue_text = system_info + issue_text + params = {"body": issue_text} + if title is None: + title = "Bug report" + params["title"] = title + issue_url = f"{github_issues}?{urllib.parse.urlencode(params)}" + + if confirm: + print(f"\n# {title}\n") + print(issue_text.strip()) + print() + print("Please consider reporting this bug to help improve aider!") + prompt = "Open a GitHub Issue pre-filled with the above error in your browser? (Y/n) " + confirmation = input(prompt).strip().lower() + + yes = not confirmation or confirmation.startswith("y") + if not yes: + return + + print("Attempting to open the issue URL in your default web browser...") + try: + if webbrowser.open(issue_url): + print("Browser window should be opened.") + except Exception: + pass + + if confirm: + print() + print() + print("You can also use this URL to file the GitHub Issue:") + print() + print(issue_url) + print() + print() + + +def exception_handler(exc_type, exc_value, exc_traceback): + # If it's a KeyboardInterrupt, just call the default handler + if issubclass(exc_type, KeyboardInterrupt): + return sys.__excepthook__(exc_type, exc_value, exc_traceback) + + # We don't want any more exceptions + sys.excepthook = None + + # Check if VERSION_CHECK_FNAME exists and delete it if so + try: + if VERSION_CHECK_FNAME.exists(): + VERSION_CHECK_FNAME.unlink() + except Exception: + pass # Swallow any errors + + # Format the traceback + tb_lines = traceback.format_exception(exc_type, exc_value, exc_traceback) + + # Replace full paths with basenames in the traceback + tb_lines_with_basenames = [] + for line in tb_lines: + try: + if "File " in line: + parts = line.split('"') + if len(parts) > 1: + full_path = parts[1] + basename = os.path.basename(full_path) + line = line.replace(full_path, basename) + except Exception: + pass + tb_lines_with_basenames.append(line) + + tb_text = "".join(tb_lines_with_basenames) + + # Find the innermost frame + innermost_tb = exc_traceback + while innermost_tb.tb_next: + innermost_tb = innermost_tb.tb_next + + # Get the filename and line number from the innermost frame + filename = innermost_tb.tb_frame.f_code.co_filename + line_number = innermost_tb.tb_lineno + try: + basename = os.path.basename(filename) + except Exception: + basename = filename + + # Get the exception type name + exception_type = exc_type.__name__ + + # Prepare the issue text + issue_text = f"An uncaught exception occurred:\n\n{FENCE}\n{tb_text}\n{FENCE}" + + # Prepare the title + title = f"Uncaught {exception_type} in {basename} line {line_number}" + + # Report the issue + report_github_issue(issue_text, title=title) + + # Call the default exception handler + sys.__excepthook__(exc_type, exc_value, exc_traceback) + + +def report_uncaught_exceptions(): + """ + Set up the global exception handler to report uncaught exceptions. + """ + sys.excepthook = exception_handler + + +def dummy_function1(): + def dummy_function2(): + def dummy_function3(): + raise ValueError("boo") + + dummy_function3() + + dummy_function2() + + +def main(): + report_uncaught_exceptions() + + dummy_function1() + + title = None + if len(sys.argv) > 2: + # Use the first command-line argument as the title and the second as the issue text + title = sys.argv[1] + issue_text = sys.argv[2] + elif len(sys.argv) > 1: + # Use the first command-line argument as the issue text + issue_text = sys.argv[1] + else: + # Read from stdin if no argument is provided + print("Enter the issue title (optional, press Enter to skip):") + title = input().strip() + if not title: + title = None + print("Enter the issue text (Ctrl+D to finish):") + issue_text = sys.stdin.read().strip() + + report_github_issue(issue_text, title) + + +if __name__ == "__main__": + main() diff --git a/aider/resources/__init__.py b/aider/resources/__init__.py new file mode 100644 index 000000000..f7ca4efbe --- /dev/null +++ b/aider/resources/__init__.py @@ -0,0 +1,3 @@ +# This ensures that importlib_resources.files("aider.resources") +# doesn't raise ImportError, even if there are no other files in this +# dir. diff --git a/aider/resources/model-metadata.json b/aider/resources/model-metadata.json new file mode 100644 index 000000000..e69de29bb diff --git a/aider/run_cmd.py b/aider/run_cmd.py new file mode 100644 index 000000000..69d5bd7c6 --- /dev/null +++ b/aider/run_cmd.py @@ -0,0 +1,132 @@ +import os +import platform +import subprocess +import sys +from io import BytesIO + +import pexpect +import psutil + + +def run_cmd(command, verbose=False, error_print=None, cwd=None): + try: + if sys.stdin.isatty() and hasattr(pexpect, "spawn") and platform.system() != "Windows": + return run_cmd_pexpect(command, verbose, cwd) + + return run_cmd_subprocess(command, verbose, cwd) + except OSError as e: + error_message = f"Error occurred while running command '{command}': {str(e)}" + if error_print is None: + print(error_message) + else: + error_print(error_message) + return 1, error_message + + +def get_windows_parent_process_name(): + try: + current_process = psutil.Process() + while True: + parent = current_process.parent() + if parent is None: + break + parent_name = parent.name().lower() + if parent_name in ["powershell.exe", "cmd.exe"]: + return parent_name + current_process = parent + return None + except Exception: + return None + + +def run_cmd_subprocess(command, verbose=False, cwd=None): + if verbose: + print("Using run_cmd_subprocess:", command) + + try: + shell = os.environ.get("SHELL", "/bin/sh") + parent_process = None + + # Determine the appropriate shell + if platform.system() == "Windows": + parent_process = get_windows_parent_process_name() + if parent_process == "powershell.exe": + command = f"powershell -Command {command}" + + if verbose: + print("Running command:", command) + print("SHELL:", shell) + if platform.system() == "Windows": + print("Parent process:", parent_process) + + process = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + shell=True, + encoding=sys.stdout.encoding, + errors="replace", + bufsize=0, # Set bufsize to 0 for unbuffered output + universal_newlines=True, + cwd=cwd, + ) + + output = [] + while True: + chunk = process.stdout.read(1) + if not chunk: + break + print(chunk, end="", flush=True) # Print the chunk in real-time + output.append(chunk) # Store the chunk for later use + + process.wait() + return process.returncode, "".join(output) + except Exception as e: + return 1, str(e) + + +def run_cmd_pexpect(command, verbose=False, cwd=None): + """ + Run a shell command interactively using pexpect, capturing all output. + + :param command: The command to run as a string. + :param verbose: If True, print output in real-time. + :return: A tuple containing (exit_status, output) + """ + if verbose: + print("Using run_cmd_pexpect:", command) + + output = BytesIO() + + def output_callback(b): + output.write(b) + return b + + try: + # Use the SHELL environment variable, falling back to /bin/sh if not set + shell = os.environ.get("SHELL", "/bin/sh") + if verbose: + print("With shell:", shell) + + if os.path.exists(shell): + # Use the shell from SHELL environment variable + if verbose: + print("Running pexpect.spawn with shell:", shell) + child = pexpect.spawn(shell, args=["-c", command], encoding="utf-8", cwd=cwd) + else: + # Fall back to spawning the command directly + if verbose: + print("Running pexpect.spawn without shell.") + child = pexpect.spawn(command, encoding="utf-8", cwd=cwd) + + # Transfer control to the user, capturing output + child.interact(output_filter=output_callback) + + # Wait for the command to finish and get the exit status + child.close() + return child.exitstatus, output.getvalue().decode("utf-8", errors="replace") + + except (pexpect.ExceptionPexpect, TypeError, ValueError) as e: + error_msg = f"Error running command {command}: {e}" + return 1, error_msg diff --git a/aider/scrape.py b/aider/scrape.py index 282bf7cdc..7977a8548 100755 --- a/aider/scrape.py +++ b/aider/scrape.py @@ -131,7 +131,9 @@ class Scraper: # Internals... def scrape_with_playwright(self, url): - import playwright + import playwright # noqa: F401 + from playwright.sync_api import Error as PlaywrightError + from playwright.sync_api import TimeoutError as PlaywrightTimeoutError from playwright.sync_api import sync_playwright with sync_playwright() as p: @@ -156,18 +158,20 @@ class Scraper: response = None try: response = page.goto(url, wait_until="networkidle", timeout=5000) - except playwright._impl._errors.TimeoutError: + except PlaywrightTimeoutError: self.print_error(f"Timeout while loading {url}") - except playwright._impl._errors.Error as e: + except PlaywrightError as e: self.print_error(f"Error navigating to {url}: {str(e)}") return None, None try: content = page.content() - mime_type = ( - response.header_value("content-type").split(";")[0] if response else None - ) - except playwright._impl._errors.Error as e: + mime_type = None + if response: + content_type = response.header_value("content-type") + if content_type: + mime_type = content_type.split(";")[0] + except PlaywrightError as e: self.print_error(f"Error retrieving page content: {str(e)}") content = None mime_type = None @@ -181,7 +185,9 @@ class Scraper: headers = {"User-Agent": f"Mozilla./5.0 ({aider_user_agent})"} try: - with httpx.Client(headers=headers, verify=self.verify_ssl) as client: + with httpx.Client( + headers=headers, verify=self.verify_ssl, follow_redirects=True + ) as client: response = client.get(url) response.raise_for_status() return response.text, response.headers.get("content-type", "").split(";")[0] @@ -220,7 +226,10 @@ class Scraper: if not self.pandoc_available: return page_source - md = pypandoc.convert_text(page_source, "markdown", format="html") + try: + md = pypandoc.convert_text(page_source, "markdown", format="html") + except OSError: + return page_source md = re.sub(r"", " ", md) md = re.sub(r"

", " ", md) diff --git a/aider/sendchat.py b/aider/sendchat.py index 1914a618b..3d1224bc6 100644 --- a/aider/sendchat.py +++ b/aider/sendchat.py @@ -1,9 +1,9 @@ import hashlib import json - -import backoff +import time from aider.dump import dump # noqa: F401 +from aider.exceptions import LiteLLMExceptions from aider.llm import litellm # from diskcache import Cache @@ -13,59 +13,32 @@ CACHE_PATH = "~/.aider.send.cache.v1" CACHE = None # CACHE = Cache(CACHE_PATH) - -def retry_exceptions(): - import httpx - - return ( - httpx.ConnectError, - httpx.RemoteProtocolError, - httpx.ReadTimeout, - litellm.exceptions.APIConnectionError, - litellm.exceptions.APIError, - litellm.exceptions.RateLimitError, - litellm.exceptions.ServiceUnavailableError, - litellm.exceptions.Timeout, - litellm.exceptions.InternalServerError, - litellm.llms.anthropic.AnthropicError, - ) - - -def lazy_litellm_retry_decorator(func): - def wrapper(*args, **kwargs): - decorated_func = backoff.on_exception( - backoff.expo, - retry_exceptions(), - max_time=60, - on_backoff=lambda details: print( - f"{details.get('exception', 'Exception')}\nRetry in {details['wait']:.1f} seconds." - ), - )(func) - return decorated_func(*args, **kwargs) - - return wrapper +RETRY_TIMEOUT = 60 def send_completion( - model_name, messages, functions, stream, temperature=0, extra_headers=None, max_tokens=None + model_name, + messages, + functions, + stream, + temperature=0, + extra_params=None, ): - from aider.llm import litellm - kwargs = dict( model=model_name, messages=messages, - temperature=temperature, stream=stream, ) + if temperature is not None: + kwargs["temperature"] = temperature if functions is not None: function = functions[0] kwargs["tools"] = [dict(type="function", function=function)] kwargs["tool_choice"] = {"type": "function", "function": {"name": function["name"]}} - if extra_headers is not None: - kwargs["extra_headers"] = extra_headers - if max_tokens is not None: - kwargs["max_tokens"] = max_tokens + + if extra_params is not None: + kwargs.update(extra_params) key = json.dumps(kwargs, sort_keys=True).encode() @@ -75,8 +48,6 @@ def send_completion( if not stream and CACHE is not None and key in CACHE: return hash_object, CACHE[key] - # del kwargs['stream'] - res = litellm.completion(**kwargs) if not stream and CACHE is not None: @@ -85,15 +56,42 @@ def send_completion( return hash_object, res -@lazy_litellm_retry_decorator -def simple_send_with_retries(model_name, messages): - try: - _hash, response = send_completion( - model_name=model_name, - messages=messages, - functions=None, - stream=False, - ) - return response.choices[0].message.content - except (AttributeError, litellm.exceptions.BadRequestError): - return +def simple_send_with_retries(model_name, messages, extra_params=None): + litellm_ex = LiteLLMExceptions() + + retry_delay = 0.125 + while True: + try: + kwargs = { + "model_name": model_name, + "messages": messages, + "functions": None, + "stream": False, + "extra_params": extra_params, + } + + _hash, response = send_completion(**kwargs) + if not response or not hasattr(response, "choices") or not response.choices: + return None + return response.choices[0].message.content + except litellm_ex.exceptions_tuple() as err: + ex_info = litellm_ex.get_ex_info(err) + + print(str(err)) + if ex_info.description: + print(ex_info.description) + + should_retry = ex_info.retry + if should_retry: + retry_delay *= 2 + if retry_delay > RETRY_TIMEOUT: + should_retry = False + + if not should_retry: + return None + + print(f"Retrying in {retry_delay:.1f} seconds...") + time.sleep(retry_delay) + continue + except AttributeError: + return None diff --git a/aider/special.py b/aider/special.py new file mode 100644 index 000000000..9d2e92e6e --- /dev/null +++ b/aider/special.py @@ -0,0 +1,202 @@ +import os + +ROOT_IMPORTANT_FILES = [ + # Version Control + ".gitignore", + ".gitattributes", + # Documentation + "README", + "README.md", + "README.txt", + "README.rst", + "CONTRIBUTING", + "CONTRIBUTING.md", + "CONTRIBUTING.txt", + "CONTRIBUTING.rst", + "LICENSE", + "LICENSE.md", + "LICENSE.txt", + "CHANGELOG", + "CHANGELOG.md", + "CHANGELOG.txt", + "CHANGELOG.rst", + "SECURITY", + "SECURITY.md", + "SECURITY.txt", + "CODEOWNERS", + # Package Management and Dependencies + "requirements.txt", + "Pipfile", + "Pipfile.lock", + "pyproject.toml", + "setup.py", + "setup.cfg", + "package.json", + "package-lock.json", + "yarn.lock", + "npm-shrinkwrap.json", + "Gemfile", + "Gemfile.lock", + "composer.json", + "composer.lock", + "pom.xml", + "build.gradle", + "build.sbt", + "go.mod", + "go.sum", + "Cargo.toml", + "Cargo.lock", + "mix.exs", + "rebar.config", + "project.clj", + "Podfile", + "Cartfile", + "dub.json", + "dub.sdl", + # Configuration and Settings + ".env", + ".env.example", + ".editorconfig", + "tsconfig.json", + "jsconfig.json", + ".babelrc", + "babel.config.js", + ".eslintrc", + ".eslintignore", + ".prettierrc", + ".stylelintrc", + "tslint.json", + ".pylintrc", + ".flake8", + ".rubocop.yml", + ".scalafmt.conf", + ".dockerignore", + ".gitpod.yml", + "sonar-project.properties", + "renovate.json", + "dependabot.yml", + ".pre-commit-config.yaml", + "mypy.ini", + "tox.ini", + ".yamllint", + "pyrightconfig.json", + # Build and Compilation + "webpack.config.js", + "rollup.config.js", + "parcel.config.js", + "gulpfile.js", + "Gruntfile.js", + "build.xml", + "build.boot", + "project.json", + "build.cake", + "MANIFEST.in", + # Testing + "pytest.ini", + "phpunit.xml", + "karma.conf.js", + "jest.config.js", + "cypress.json", + ".nycrc", + ".nycrc.json", + # CI/CD + ".travis.yml", + ".gitlab-ci.yml", + "Jenkinsfile", + "azure-pipelines.yml", + "bitbucket-pipelines.yml", + "appveyor.yml", + "circle.yml", + ".circleci/config.yml", + ".github/dependabot.yml", + "codecov.yml", + ".coveragerc", + # Docker and Containers + "Dockerfile", + "docker-compose.yml", + "docker-compose.override.yml", + # Cloud and Serverless + "serverless.yml", + "firebase.json", + "now.json", + "netlify.toml", + "vercel.json", + "app.yaml", + "terraform.tf", + "main.tf", + "cloudformation.yaml", + "cloudformation.json", + "ansible.cfg", + "kubernetes.yaml", + "k8s.yaml", + # Database + "schema.sql", + "liquibase.properties", + "flyway.conf", + # Framework-specific + "next.config.js", + "nuxt.config.js", + "vue.config.js", + "angular.json", + "gatsby-config.js", + "gridsome.config.js", + # API Documentation + "swagger.yaml", + "swagger.json", + "openapi.yaml", + "openapi.json", + # Development environment + ".nvmrc", + ".ruby-version", + ".python-version", + "Vagrantfile", + # Quality and metrics + ".codeclimate.yml", + "codecov.yml", + # Documentation + "mkdocs.yml", + "_config.yml", + "book.toml", + "readthedocs.yml", + ".readthedocs.yaml", + # Package registries + ".npmrc", + ".yarnrc", + # Linting and formatting + ".isort.cfg", + ".markdownlint.json", + ".markdownlint.yaml", + # Security + ".bandit", + ".secrets.baseline", + # Misc + ".pypirc", + ".gitkeep", + ".npmignore", +] + + +# Normalize the lists once +NORMALIZED_ROOT_IMPORTANT_FILES = set(os.path.normpath(path) for path in ROOT_IMPORTANT_FILES) + + +def is_important(file_path): + file_name = os.path.basename(file_path) + dir_name = os.path.normpath(os.path.dirname(file_path)) + normalized_path = os.path.normpath(file_path) + + # Check for GitHub Actions workflow files + if dir_name == os.path.normpath(".github/workflows") and file_name.endswith(".yml"): + return True + + return normalized_path in NORMALIZED_ROOT_IMPORTANT_FILES + + +def filter_important_files(file_paths): + """ + Filter a list of file paths to return only those that are commonly important in codebases. + + :param file_paths: List of file paths to check + :return: List of file paths that match important file patterns + """ + return list(filter(is_important, file_paths)) diff --git a/aider/urls.py b/aider/urls.py index 24e830766..81c3558e8 100644 --- a/aider/urls.py +++ b/aider/urls.py @@ -8,3 +8,9 @@ model_warnings = "https://aider.chat/docs/llms/warnings.html" token_limits = "https://aider.chat/docs/troubleshooting/token-limits.html" llms = "https://aider.chat/docs/llms.html" large_repos = "https://aider.chat/docs/faq.html#can-i-use-aider-in-a-large-mono-repo" +github_issues = "https://github.com/Aider-AI/aider/issues/new" +git_index_version = "https://github.com/Aider-AI/aider/issues/211" +install_properly = "https://aider.chat/docs/troubleshooting/imports.html" +analytics = "https://aider.chat/docs/more/analytics.html" +release_notes = "https://aider.chat/HISTORY.html#release-notes" +edit_formats = "https://aider.chat/docs/more/edit-formats.html" diff --git a/aider/utils.py b/aider/utils.py index 7191d6e3c..e91e5deb0 100644 --- a/aider/utils.py +++ b/aider/utils.py @@ -1,5 +1,8 @@ import itertools import os +import platform +import shlex +import shutil import subprocess import sys import tempfile @@ -10,7 +13,7 @@ import git from aider.dump import dump # noqa: F401 -IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".webp"} +IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".webp", ".pdf"} class IgnorantTemporaryDirectory: @@ -191,12 +194,31 @@ def split_chat_history_markdown(text, include_tool=False): return messages +# Copied from pip, MIT license +# https://github.com/pypa/pip/blob/b989e6ef04810bbd4033a3683020bd4ddcbdb627/src/pip/_internal/utils/entrypoints.py#L73 +def get_best_invocation_for_this_python() -> str: + """Try to figure out the best way to invoke the current Python.""" + exe = sys.executable + exe_name = os.path.basename(exe) + + # Try to use the basename, if it's the first executable. + found_executable = shutil.which(exe_name) + if found_executable and os.path.samefile(found_executable, exe): + return exe_name + + # Use the full executable name, because we couldn't find something simpler. + return exe + + def get_pip_install(args): cmd = [ - sys.executable, + get_best_invocation_for_this_python(), "-m", "pip", "install", + "--upgrade", + "--upgrade-strategy", + "only-if-needed", ] cmd += args return cmd @@ -204,7 +226,7 @@ def get_pip_install(args): def run_install(cmd): print() - print("Installing: ", " ".join(cmd)) + print("Installing:", printable_shell_command(cmd)) try: output = [] @@ -215,6 +237,8 @@ def run_install(cmd): text=True, bufsize=1, universal_newlines=True, + encoding=sys.stdout.encoding, + errors="replace", ) spinner = Spinner("Installing...") @@ -251,8 +275,12 @@ class Spinner: self.start_time = time.time() self.last_update = 0 self.visible = False + self.is_tty = sys.stdout.isatty() def step(self): + if not self.is_tty: + return + current_time = time.time() if not self.visible and current_time - self.start_time >= 0.5: self.visible = True @@ -268,7 +296,7 @@ class Spinner: print(f"\r{self.text} {next(self.spinner_chars)}\r{self.text} ", end="", flush=True) def end(self): - if self.visible: + if self.visible and self.is_tty: print("\r" + " " * (len(self.text) + 3)) @@ -281,29 +309,76 @@ def find_common_root(abs_fnames): return safe_abs_path(os.getcwd()) -def check_pip_install_extra(io, module, prompt, pip_install_cmd): +def format_tokens(count): + if count < 1000: + return f"{count}" + elif count < 10000: + return f"{count / 1000:.1f}k" + else: + return f"{round(count / 1000)}k" + + +def touch_file(fname): + fname = Path(fname) try: - __import__(module) + fname.parent.mkdir(parents=True, exist_ok=True) + fname.touch() return True - except (ImportError, ModuleNotFoundError): - pass + except OSError: + return False + + +def check_pip_install_extra(io, module, prompt, pip_install_cmd, self_update=False): + if module: + try: + __import__(module) + return True + except (ImportError, ModuleNotFoundError, RuntimeError): + pass cmd = get_pip_install(pip_install_cmd) - io.tool_error(prompt) - if not io.confirm_ask("Run pip install?", default="y", subject=" ".join(cmd)): + if prompt: + io.tool_warning(prompt) + + if self_update and platform.system() == "Windows": + io.tool_output("Run this command to update:") + print() + print(printable_shell_command(cmd)) # plain print so it doesn't line-wrap + return + + if not io.confirm_ask("Run pip install?", default="y", subject=printable_shell_command(cmd)): return success, output = run_install(cmd) if success: + if not module: + return True try: __import__(module) return True - except (ImportError, ModuleNotFoundError) as err: + except (ImportError, ModuleNotFoundError, RuntimeError) as err: io.tool_error(str(err)) pass io.tool_error(output) print() - print(f"Failed to install {pip_install_cmd[0]}") + print("Install failed, try running this command manually:") + print(printable_shell_command(cmd)) + + +def printable_shell_command(cmd_list): + """ + Convert a list of command arguments to a properly shell-escaped string. + + Args: + cmd_list (list): List of command arguments. + + Returns: + str: Shell-escaped command string. + """ + if platform.system() == "Windows": + return subprocess.list2cmdline(cmd_list) + else: + return shlex.join(cmd_list) diff --git a/aider/versioncheck.py b/aider/versioncheck.py index 3f69aeb6f..ac511a022 100644 --- a/aider/versioncheck.py +++ b/aider/versioncheck.py @@ -9,13 +9,63 @@ import aider from aider import utils from aider.dump import dump # noqa: F401 +VERSION_CHECK_FNAME = Path.home() / ".aider" / "caches" / "versioncheck" + + +def install_from_main_branch(io): + """ + Install the latest version of aider from the main branch of the GitHub repository. + """ + + return utils.check_pip_install_extra( + io, + None, + "Install the development version of aider from the main branch?", + ["git+https://github.com/Aider-AI/aider.git"], + self_update=True, + ) + + +def install_upgrade(io, latest_version=None): + """ + Install the latest version of aider from PyPI. + """ + + if latest_version: + new_ver_text = f"Newer aider version v{latest_version} is available." + else: + new_ver_text = "Install latest version of aider?" + + docker_image = os.environ.get("AIDER_DOCKER_IMAGE") + if docker_image: + text = f""" +{new_ver_text} To upgrade, run: + + docker pull {docker_image} +""" + io.tool_warning(text) + return True + + success = utils.check_pip_install_extra( + io, + None, + new_ver_text, + ["aider-chat"], + self_update=True, + ) + + if success: + io.tool_output("Re-run aider to use new version.") + sys.exit() + + return + def check_version(io, just_check=False, verbose=False): - fname = Path.home() / ".aider" / "caches" / "versioncheck" - if not just_check and fname.exists(): + if not just_check and VERSION_CHECK_FNAME.exists(): day = 60 * 60 * 24 - since = time.time() - fname.stat().st_mtime - if since < day: + since = time.time() - os.path.getmtime(VERSION_CHECK_FNAME) + if 0 < since < day: if verbose: hours = since / 60 / 60 io.tool_output(f"Too soon to check version: {hours:.1f} hours") @@ -41,8 +91,11 @@ def check_version(io, just_check=False, verbose=False): io.tool_error(f"Error checking pypi for new version: {err}") return False finally: - fname.parent.mkdir(parents=True, exist_ok=True) - fname.touch() + VERSION_CHECK_FNAME.parent.mkdir(parents=True, exist_ok=True) + VERSION_CHECK_FNAME.touch() + + ### + # is_update_available = True if just_check or verbose: if is_update_available: @@ -56,27 +109,5 @@ def check_version(io, just_check=False, verbose=False): if not is_update_available: return False - docker_image = os.environ.get("AIDER_DOCKER_IMAGE") - if docker_image: - text = f""" -Newer aider version v{latest_version} is available. To upgrade, run: - - docker pull {docker_image} -""" - io.tool_error(text) - return True - - cmd = utils.get_pip_install(["--upgrade", "aider-chat"]) - - text = f"Newer aider version v{latest_version} is available. To upgrade, run:" - - io.tool_error(text) - if io.confirm_ask("Run pip install?", subject=" ".join(cmd)): - success, output = utils.run_install(cmd) - if success: - io.tool_output("Re-run aider to use new version.") - sys.exit() - else: - io.tool_error(output) - + install_upgrade(io, latest_version) return True diff --git a/aider/voice.py b/aider/voice.py index d333c85e7..47fb49c6e 100644 --- a/aider/voice.py +++ b/aider/voice.py @@ -3,18 +3,25 @@ import os import queue import tempfile import time +import warnings + +from prompt_toolkit.shortcuts import prompt from aider.llm import litellm +from .dump import dump # noqa: F401 + +warnings.filterwarnings( + "ignore", message="Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work" +) + +from pydub import AudioSegment # noqa + try: import soundfile as sf except (OSError, ModuleNotFoundError): sf = None -from prompt_toolkit.shortcuts import prompt - -from .dump import dump # noqa: F401 - class SoundDeviceError(Exception): pass @@ -27,7 +34,7 @@ class Voice: threshold = 0.15 - def __init__(self): + def __init__(self, audio_format="wav"): if sf is None: raise SoundDeviceError try: @@ -37,6 +44,9 @@ class Voice: self.sd = sd except (OSError, ModuleNotFoundError): raise SoundDeviceError + if audio_format not in ["wav", "mp3", "webm"]: + raise ValueError(f"Unsupported audio format: {audio_format}") + self.audio_format = audio_format def callback(self, indata, frames, time, status): """This is called (from a separate thread) for each audio block.""" @@ -72,16 +82,24 @@ class Voice: return self.raw_record_and_transcribe(history, language) except KeyboardInterrupt: return + except SoundDeviceError as e: + print(f"Error: {e}") + print("Please ensure you have a working audio input device connected and try again.") + return def raw_record_and_transcribe(self, history, language): self.q = queue.Queue() - filename = tempfile.mktemp(suffix=".wav") + temp_wav = tempfile.mktemp(suffix=".wav") try: sample_rate = int(self.sd.query_devices(None, "input")["default_samplerate"]) except (TypeError, ValueError): sample_rate = 16000 # fallback to 16kHz if unable to query device + except self.sd.PortAudioError: + raise SoundDeviceError( + "No audio input device detected. Please check your audio settings and try again." + ) self.start_time = time.time() @@ -89,17 +107,31 @@ class Voice: with self.sd.InputStream(samplerate=sample_rate, channels=1, callback=self.callback): prompt(self.get_prompt, refresh_interval=0.1) except self.sd.PortAudioError as err: - print(err) - return + raise SoundDeviceError(f"Error accessing audio input device: {err}") - with sf.SoundFile(filename, mode="x", samplerate=sample_rate, channels=1) as file: + with sf.SoundFile(temp_wav, mode="x", samplerate=sample_rate, channels=1) as file: 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 + with open(filename, "rb") as fh: - transcript = litellm.transcription( - model="whisper-1", file=fh, prompt=history, language=language - ) + try: + transcript = litellm.transcription( + model="whisper-1", file=fh, prompt=history, language=language + ) + except Exception as err: + print(f"Unable to transcribe {filename}: {err}") + return + + if self.audio_format != "wav": + os.remove(filename) text = transcript.text return text diff --git a/aider/website/HISTORY.md b/aider/website/HISTORY.md index 50aedd428..61755d118 100644 --- a/aider/website/HISTORY.md +++ b/aider/website/HISTORY.md @@ -1,20 +1,347 @@ --- title: Release history parent: More info -nav_order: 999 +nav_order: 900 highlight_image: /assets/blame.jpg description: Release notes and stats on aider writing its own code. --- +# Release history + {% include blame.md %} +The above +[stats are based on the git commit history](/docs/faq.html#how-are-the-aider-wrote-xx-of-code-stats-computed) +of the aider repo. + +## Release notes + -# Release history + +### main branch + +- PDF support for Sonnet and Gemini models. +- Set cwd to repo root when running shell commands. +- Improved error handling for failed .gitignore file operations. +- Improved error handling for input history file permissions. +- Improved error handling for analytics file access. +- Aider wrote 85% of the code in this release. + +### Aider v0.65.1 + +- Bugfix to `--alias`. + +### Aider v0.65.0 + +- Added `--alias` config to define [custom model aliases](https://aider.chat/docs/config/model-aliases.html). +- Added `--[no-]detect-urls` flag to disable detecting and offering to scrape URLs found in the chat. +- Ollama models now default to an 8k context window. +- Added [RepoMap support for Dart language](https://aider.chat/docs/languages.html) by @malkoG. +- Ask 2.5% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html). +- Skip suggesting files that share names with files already in chat. +- `/editor` returns and prefill the file content into the prompt, so you can use `/editor` to compose messages that start with `/commands`, etc. +- Enhanced error handling for analytics. +- Improved handling of UnknownEditFormat exceptions with helpful documentation links. +- Bumped dependencies to pick up grep-ast 0.4.0 for Dart language support. +- Aider wrote 81% of the code in this release. + +### Aider v0.64.1 + +- Disable streaming for o1 on OpenRouter. + +### Aider v0.64.0 + +- Added [`/editor` command](https://aider.chat/docs/usage/commands.html) to open system editor for writing prompts, by @thehunmonkgroup. +- Full support for `gpt-4o-2024-11-20`. +- Stream o1 models by default. +- `/run` and suggested shell commands are less mysterious and now confirm that they "Added XX lines of output to the chat." +- Ask 1% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html). +- Added support for [optional multiline input tags](https://aider.chat/docs/usage/commands.html#entering-multi-line-chat-messages) with matching closing tags. +- Improved [model settings configuration](https://aider.chat/docs/config/adv-model-settings.html#global-extra-params) with support for global `extra_params` for `litellm.completion()`. +- Architect mode now asks to add files suggested by the LLM. +- Fixed bug in fuzzy model name matching. +- Added Timeout exception to handle API provider timeouts. +- Added `--show-release-notes` to control release notes display on first run of new version. +- Save empty dict to cache file on model metadata download failure, to delay retry. +- Improved error handling and code formatting. +- Aider wrote 74% of the code in this release. + +### Aider v0.63.2 + +- Fixed bug in fuzzy model name matching when litellm provider info is missing. +- Modified model metadata file loading to allow override of resource file. +- Allow recursive loading of dirs using `--read`. +- Updated dependency versions to pick up litellm fix for ollama models. +- Added exponential backoff retry when writing files to handle editor file locks. +- Updated Qwen 2.5 Coder 32B model configuration. + +### Aider v0.63.1 + +- Fixed bug in git ignored file handling. +- Improved error handling for git operations. + +### Aider v0.63.0 + +- Support for Qwen 2.5 Coder 32B. +- `/web` command just adds the page to the chat, without triggering an LLM response. +- Improved prompting for the user's preferred chat language. +- Improved handling of LiteLLM exceptions. +- Bugfix for double-counting tokens when reporting cache stats. +- Bugfix for the LLM creating new files. +- Other small bug fixes. +- Aider wrote 55% of the code in this release. + +### Aider v0.62.0 + +- Full support for Claude 3.5 Haiku + - Scored 75% on [aider's code editing leaderboard](https://aider.chat/docs/leaderboards/). + - Almost as good as Sonnet at much lower cost. + - Launch with `--haiku` to use it. +- Easily apply file edits from ChatGPT, Claude or other web apps + - Chat with ChatGPT or Claude via their web app. + - Give it your source files and ask for the changes you want. + - Use the web app's "copy response" button to copy the entire reply from the LLM. + - Run `aider --apply-clipboard-edits file-to-edit.js`. + - Aider will edit your file with the LLM's changes. +- Bugfix for creating new files. +- Aider wrote 84% of the code in this release. + +### Aider v0.61.0 + +- Load and save aider slash-commands to files: + - `/save ` command will make a file of `/add` and `/read-only` commands that recreate the current file context in the chat. + - `/load ` will replay the commands in the file. + - You can use `/load` to run any arbitrary set of slash-commands, not just `/add` and `/read-only`. + - Use `--load ` to run a list of commands on launch, before the interactive chat begins. +- Anonymous, opt-in [analytics](https://aider.chat/docs/more/analytics.html) with no personal data sharing. +- Aider follows litellm's `supports_vision` attribute to enable image support for models. +- Bugfix for when diff mode flexibly handles the model using the wrong filename. +- Displays filenames in sorted order for `/add` and `/read-only`. +- New `--no-fancy-input` switch disables prompt toolkit input, now still available with `--no-pretty`. +- Override browser config with `--no-browser` or `--no-gui`. +- Offer to open documentation URLs when errors occur. +- Properly support all o1 models, regardless of provider. +- Improved layout of filenames above input prompt. +- Better handle corrupted repomap tags cache. +- Improved handling of API errors, especially when accessing the weak model. +- Aider wrote 68% of the code in this release. + +### Aider v0.60.1 + +- Enable image support for Sonnet 10/22. +- Display filenames in sorted order. + +### Aider v0.60.0 + +- Full support for Sonnet 10/22, the new SOTA model on aider's code editing benchmark. + - Aider uses Sonnet 10/22 by default. +- Improved formatting of added and read-only files above chat prompt, by @jbellis. +- Improved support for o1 models by more flexibly parsing their nonconforming code edit replies. +- Corrected diff edit format prompt that only the first match is replaced. +- Stronger whole edit format prompt asking for clean file names. +- Now offers to add `.env` to the `.gitignore` file. +- Ships with a small model metadata json file to handle models not yet updated in litellm. +- Model settings for o1 models on azure. +- Bugfix to properly include URLs in `/help` RAG results. +- Aider wrote 49% of the code in this release. + +### Aider v0.59.1 + +- Check for obsolete `yes: true` in yaml config, show helpful error. +- Model settings for openrouter/anthropic/claude-3.5-sonnet:beta + +### Aider v0.59.0 + +- Improvements to `/read-only`: + - Now supports shell-style auto-complete of the full file system. + - Still auto-completes the full paths of the repo files like `/add`. + - Now supports globs like `src/**/*.py` +- Renamed `--yes` to `--yes-always`. + - Now uses `AIDER_YES_ALWAYS` env var and `yes-always:` yaml key. + - Existing YAML and .env files will need to be updated. + - Can still abbreviate to `--yes` on the command line. +- Config file now uses standard YAML list syntax with ` - list entries`, one per line. +- `/settings` now includes the same announcement lines that would print at launch. +- Sanity checks the `--editor-model` on launch now, same as main and weak models. +- Added `--skip-sanity-check-repo` switch to speedup launch in large repos. +- Bugfix so architect mode handles Control-C properly. +- Repo-map is deterministic now, with improved caching logic. +- Improved commit message prompt. +- Aider wrote 77% of the code in this release. + +### Aider v0.58.1 + +- Fixed bug where cache warming pings caused subsequent user messages to trigger a tight loop of LLM requests. + +### Aider v0.58.0 + +- [Use a pair of Architect/Editor models for improved coding](https://aider.chat/2024/09/26/architect.html) + - Use a strong reasoning model like o1-preview as your Architect. + - Use a cheaper, faster model like gpt-4o as your Editor. +- New `--o1-preview` and `--o1-mini` shortcuts. +- Support for new Gemini 002 models. +- Better support for Qwen 2.5 models. +- Many confirmation questions can be skipped for the rest of the session with "(D)on't ask again" response. +- Autocomplete for `/read-only` supports the entire filesystem. +- New settings for completion menu colors. +- New `/copy` command to copy the last LLM response to the clipboard. +- Renamed `/clipboard` to `/paste`. +- Will now follow HTTP redirects when scraping urls. +- New `--voice-format` switch to send voice audio as wav/mp3/webm, by @mbailey. +- ModelSettings takes `extra_params` dict to specify any extras to pass to `litellm.completion()`. +- Support for cursor shapes when in vim mode. +- Numerous bug fixes. +- Aider wrote 53% of the code in this release. + +### Aider v0.57.1 + +- Fixed dependency conflict between aider-chat[help] and [playwright]. + +### Aider v0.57.0 + +- Support for OpenAI o1 models: + - o1-preview now works well with diff edit format. + - o1-preview with diff now matches SOTA leaderboard result with whole edit format. + - `aider --model o1-mini` + - `aider --model o1-preview` +- On Windows, `/run` correctly uses PowerShell or cmd.exe. +- Support for new 08-2024 Cohere models, by @jalammar. +- Can now recursively add directories with `/read-only`. +- User input prompts now fall back to simple `input()` if `--no-pretty` or a Windows console is not available. +- Improved sanity check of git repo on startup. +- Improvements to prompt cache chunking strategy. +- Removed "No changes made to git tracked files". +- Numerous bug fixes for corner case crashes. +- Updated all dependency versions. +- Aider wrote 70% of the code in this release. + +### Aider v0.56.0 + +- Enables prompt caching for Sonnet via OpenRouter by @fry69 +- Enables 8k output tokens for Sonnet via VertexAI and DeepSeek V2.5. +- New `/report` command to open your browser with a pre-populated GitHub Issue. +- New `--chat-language` switch to set the spoken language. +- Now `--[no-]suggest-shell-commands` controls both prompting for and offering to execute shell commands. +- Check key imports on launch, provide helpful error message if dependencies aren't available. +- Renamed `--models` to `--list-models` by @fry69. +- Numerous bug fixes for corner case crashes. +- Aider wrote 56% of the code in this release. + +### Aider v0.55.0 + +- Only print the pip command when self updating on Windows, without running it. +- Converted many error messages to warning messages. +- Added `--tool-warning-color` setting. +- Blanket catch and handle git errors in any `/command`. +- Catch and handle glob errors in `/add`, errors writing files. +- Disabled built in linter for typescript. +- Catch and handle terminals which don't support pretty output. +- Catch and handle playwright and pandoc errors. +- Catch `/voice` transcription exceptions, show the WAV file so the user can recover it. +- Aider wrote 53% of the code in this release. + +### Aider v0.54.12 + +- Switched to `vX.Y.Z.dev` version naming. + +### Aider v0.54.11 + +- Improved printed pip command output on Windows. + +### Aider v0.54.10 + +- Bugfix to test command in platform info. + +### Aider v0.54.9 + +- Include important devops files in the repomap. +- Print quoted pip install commands to the user. +- Adopt setuptools_scm to provide dev versions with git hashes. +- Share active test and lint commands with the LLM. +- Catch and handle most errors creating new files, reading existing files. +- Catch and handle most git errors. +- Added --verbose debug output for shell commands. + +### Aider v0.54.8 + +- Startup QOL improvements: + - Sanity check the git repo and exit gracefully on problems. + - Pause for confirmation after model sanity check to allow user to review warnings. +- Bug fix for shell commands on Windows. +- Do not fuzzy match filenames when LLM is creating a new file, by @ozapinq +- Numerous corner case bug fixes submitted via new crash report -> GitHub Issue feature. +- Crash reports now include python version, OS, etc. + +### Aider v0.54.7 + +- Offer to submit a GitHub issue pre-filled with uncaught exception info. +- Bugfix for infinite output. + +### Aider v0.54.6 + +- New `/settings` command to show active settings. +- Only show cache warming status update if `--verbose`. + +### Aider v0.54.5 + +- Bugfix for shell commands on Windows. +- Refuse to make git repo in $HOME, warn user. +- Don't ask again in current session about a file the user has said not to add to the chat. +- Added `--update` as an alias for `--upgrade`. + +### Aider v0.54.4 + +- Bugfix to completions for `/model` command. +- Bugfix: revert home dir special case. + +### Aider v0.54.3 + +- Dependency `watchdog<5` for docker image. + +### Aider v0.54.2 + +- When users launch aider in their home dir, help them find/create a repo in a subdir. +- Added missing `pexpect` dependency. + +### Aider v0.54.0 + +- Added model settings for `gemini/gemini-1.5-pro-exp-0827` and `gemini/gemini-1.5-flash-exp-0827`. +- Shell and `/run` commands can now be interactive in environments where a pty is available. +- Optionally share output of suggested shell commands back to the LLM. +- New `--[no-]suggest-shell-commands` switch to configure shell commands. +- Performance improvements for autocomplete in large/mono repos. +- New `--upgrade` switch to install latest version of aider from pypi. +- Bugfix to `--show-prompt`. +- Disabled automatic reply to the LLM on `/undo` for all models. +- Removed pager from `/web` output. +- Aider wrote 64% of the code in this release. + +### Aider v0.53.0 + +- [Keep your prompt cache from expiring](https://aider.chat/docs/usage/caching.html#preventing-cache-expiration) with `--cache-keepalive-pings`. + - Pings the API every 5min to keep the cache warm. +- You can now bulk accept/reject a series of add url and run shell confirmations. +- Improved matching of filenames from S/R blocks with files in chat. +- Stronger prompting for Sonnet to make edits in code chat mode. +- Stronger prompting for the LLM to specify full file paths. +- Improved shell command prompting. +- Weak model now uses `extra_headers`, to support Anthropic beta features. +- New `--install-main-branch` to update to the latest dev version of aider. +- Improved error messages on attempt to add not-git subdir to chat. +- Show model metadata info on `--verbose`. +- Improved warnings when LLMs env variables aren't set. +- Bugfix to windows filenames which contain `\_`. +- Aider wrote 59% of the code in this release. + +### Aider v0.52.1 + +- Bugfix for NameError when applying edits. ### Aider v0.52.0 @@ -536,7 +863,7 @@ cog.out(text) ### Aider v0.14.0 - [Support for Claude2 and other LLMs via OpenRouter](https://aider.chat/docs/faq.html#accessing-other-llms-with-openrouter) by @joshuavial -- Documentation for [running the aider benchmarking suite](https://github.com/paul-gauthier/aider/tree/main/benchmark) +- Documentation for [running the aider benchmarking suite](https://github.com/Aider-AI/aider/tree/main/benchmark) - Aider now requires Python >= 3.9 @@ -581,7 +908,7 @@ cog.out(text) - Added `/git` command to run git from inside aider chats. - Use Meta-ENTER (Esc+ENTER in some environments) to enter multiline chat messages. -- Create a `.gitignore` with `.aider*` to prevent users from accidentaly adding aider files to git. +- Create a `.gitignore` with `.aider*` to prevent users from accidentally adding aider files to git. - Check pypi for newer versions and notify user. - Updated keyboard interrupt logic so that 2 ^C in 2 seconds always forces aider to exit. - Provide GPT with detailed error if it makes a bad edit block, ask for a retry. diff --git a/aider/website/_config.yml b/aider/website/_config.yml index b95a2a158..b735e8b0e 100644 --- a/aider/website/_config.yml +++ b/aider/website/_config.yml @@ -24,7 +24,7 @@ exclude: aux_links: "GitHub": - - "https://github.com/paul-gauthier/aider" + - "https://github.com/Aider-AI/aider" "Discord": - "https://discord.gg/Tv2uQnR88V" "Blog": @@ -32,13 +32,17 @@ aux_links: nav_external_links: - title: "GitHub" - url: "https://github.com/paul-gauthier/aider" + url: "https://github.com/Aider-AI/aider" - title: "Discord" url: "https://discord.gg/Tv2uQnR88V" -repository: paul-gauthier/aider +repository: Aider-AI/aider callouts: tip: title: Tip - color: green \ No newline at end of file + color: green + note: + title: Note + color: yellow + \ No newline at end of file diff --git a/aider/website/_data/architect.yml b/aider/website/_data/architect.yml new file mode 100644 index 000000000..62d4cb7cf --- /dev/null +++ b/aider/website/_data/architect.yml @@ -0,0 +1,492 @@ +- dirname: 2024-09-25-21-17-19--architect-sonnet-sonnet-diff + test_cases: 133 + model: claude-3.5-sonnet + editor_model: claude-3.5-sonnet + editor_edit_format: diff + edit_format: architect + commit_hash: c18d6a8-dirty + pass_rate_1: 62.4 + pass_rate_2: 80.5 + percent_cases_well_formed: 100.0 + error_outputs: 3 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 183 + lazy_comments: 6 + syntax_errors: 9 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-09-25 + versions: 0.57.2.dev + seconds_per_case: 25.1 + total_cost: 4.9502 + +- dirname: 2024-07-04-14-32-08--claude-3.5-sonnet-diff-continue + test_cases: 133 + model: claude-3.5-sonnet + edit_format: diff + commit_hash: 35f21b5 + pass_rate_1: 57.1 + pass_rate_2: 77.4 + percent_cases_well_formed: 99.2 + error_outputs: 23 + released: 2024-06-20 + num_malformed_responses: 4 + num_with_malformed_responses: 1 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --sonnet + date: 2024-07-04 + versions: 0.42.1-dev + seconds_per_case: 17.6 + total_cost: 3.6346 + +- dirname: 2024-09-25-21-25-01--architect-o1mini-4o-jr-diff + test_cases: 133 + model: o1-mini + editor_model: gpt-4o + editor_edit_format: diff + edit_format: architect + commit_hash: 3f682ed-dirty, 25e833b + pass_rate_1: 51.1 + pass_rate_2: 70.7 + percent_cases_well_formed: 100.0 + error_outputs: 12 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 214 + lazy_comments: 6 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model o1-mini + date: 2024-09-25 + versions: 0.57.2.dev + seconds_per_case: 23.7 + total_cost: 9.3158 + +- dirname: 2024-09-26-15-05-58--architect-o1mini-deep-jr-whole + test_cases: 133 + model: o1-mini + edit_format: architect + commit_hash: 1676653-dirty + editor_model: deepseek + editor_edit_format: whole + pass_rate_1: 51.9 + pass_rate_2: 71.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 199 + lazy_comments: 11 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model o1-mini + date: 2024-09-26 + versions: 0.57.2.dev + seconds_per_case: 48.2 + total_cost: 5.6069 + +- dirname: 2024-09-25-21-33-40--architect-4o-4o-jr-diff + test_cases: 133 + model: gpt-4o + editor_model: gpt-4o + editor_edit_format: diff + edit_format: architect + commit_hash: 9f3cd92 + pass_rate_1: 56.4 + pass_rate_2: 75.2 + percent_cases_well_formed: 100.0 + error_outputs: 13 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 207 + lazy_comments: 8 + syntax_errors: 1 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model gpt-4o + date: 2024-09-25 + versions: 0.57.2.dev + seconds_per_case: 18.2 + total_cost: 6.0918 + +- dirname: 2024-09-21-16-45-11--o1-preview-flex-sr-markers + test_cases: 133 + model: o1-preview + edit_format: diff + commit_hash: 5493654-dirty + pass_rate_1: 57.9 + pass_rate_2: 79.7 + percent_cases_well_formed: 93.2 + error_outputs: 11 + num_malformed_responses: 11 + num_with_malformed_responses: 9 + user_asks: 3 + lazy_comments: 0 + syntax_errors: 10 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model o1-preview + date: 2024-09-21 + versions: 0.56.1.dev + seconds_per_case: 80.9 + total_cost: 63.9190 + +- dirname: 2024-09-25-21-39-05--architect-o1preview-4o-jr-diff + test_cases: 133 + model: o1-preview + editor_model: gpt-4o + editor_edit_format: diff + edit_format: architect + commit_hash: 9f3cd92 + pass_rate_1: 63.2 + pass_rate_2: 80.5 + percent_cases_well_formed: 100.0 + error_outputs: 23 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 191 + lazy_comments: 2 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model o1-preview + date: 2024-09-25 + versions: 0.57.2.dev + seconds_per_case: 42.3 + total_cost: 39.3766 + +- dirname: 2024-09-25-21-52-42--architect-o1preview-sonnet-jr-diff + test_cases: 133 + model: o1-preview + editor_model: claude-3.5-sonnet + editor_edit_format: diff + edit_format: architect + commit_hash: 9f3cd92 + editor_model: claude-3-5-sonnet + pass_rate_1: 60.9 + pass_rate_2: 82.7 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 180 + lazy_comments: 3 + syntax_errors: 9 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model o1-preview + date: 2024-09-25 + versions: 0.57.2.dev + seconds_per_case: 44.9 + total_cost: 37.6192 + +- dirname: 2024-09-21-16-40-56--o1-mini-flex-sr-markers + test_cases: 36 + model: o1-mini + edit_format: diff + commit_hash: 5493654 + pass_rate_1: 50.0 + pass_rate_2: 61.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 3 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model o1-mini + date: 2024-09-21 + versions: 0.56.1.dev + seconds_per_case: 26.7 + total_cost: 2.4226 + +- dirname: 2024-09-25-23-12-14--architect-o1mini-deep-jr-diff + test_cases: 133 + model: o1-mini + edit_format: architect + commit_hash: 9f3cd92-dirty + editor_model: deepseek + editor_edit_format: diff + pass_rate_1: 48.9 + pass_rate_2: 69.2 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 202 + lazy_comments: 12 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model o1-mini + date: 2024-09-25 + versions: 0.57.2.dev + seconds_per_case: 52.2 + total_cost: 5.7927 + +- dirname: 2024-09-25-23-18-16--architect-o1preview-deep-jr-diff + test_cases: 133 + model: o1-preview + edit_format: architect + commit_hash: 9f3cd92-dirty + editor_model: deepseek + editor_edit_format: diff + pass_rate_1: 64.7 + pass_rate_2: 80.5 + percent_cases_well_formed: 100.0 + error_outputs: 5 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 180 + lazy_comments: 2 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model o1-preview + date: 2024-09-25 + versions: 0.57.2.dev + seconds_per_case: 73.2 + total_cost: 35.7887 + +- dirname: 2024-09-25-23-30-36--architect-o1preview-deep-jr-whole + test_cases: 133 + model: o1-preview + edit_format: architect + commit_hash: 9f3cd92-dirty + editor_model: deepseek + editor_edit_format: whole + pass_rate_1: 63.9 + pass_rate_2: 85.0 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 181 + lazy_comments: 12 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model o1-preview + date: 2024-09-25 + versions: 0.57.2.dev + seconds_per_case: 67.4 + total_cost: 35.3152 + +- dirname: 2024-09-26-15-15-17--architect-sonnet-deep-jr-whole + test_cases: 133 + model: claude-3.5-sonnet + edit_format: architect + commit_hash: bc1559f-dirty + editor_model: deepseek + editor_edit_format: whole + pass_rate_1: 61.7 + pass_rate_2: 78.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 184 + lazy_comments: 5 + syntax_errors: 9 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-09-26 + versions: 0.57.2.dev + seconds_per_case: 37.2 + total_cost: 2.1510 + +- dirname: 2024-09-26-15-33-28--costs-gpt4o-diff + test_cases: 133 + model: gpt-4o + edit_format: diff + commit_hash: 89aa385-dirty + pass_rate_1: 55.6 + pass_rate_2: 71.4 + percent_cases_well_formed: 97.7 + error_outputs: 5 + num_malformed_responses: 5 + num_with_malformed_responses: 3 + user_asks: 10 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model gpt-4o + date: 2024-09-26 + versions: 0.57.2.dev + seconds_per_case: 9.7 + total_cost: 3.8088 + +- dirname: 2024-09-26-15-41-08--architect-4o-deep-jr-whole + test_cases: 133 + model: gpt-4o + edit_format: architect + commit_hash: 89aa385-dirty + editor_model: deepseek + editor_edit_format: whole + pass_rate_1: 60.9 + pass_rate_2: 73.7 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 187 + lazy_comments: 12 + syntax_errors: 5 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gpt-4o + date: 2024-09-26 + versions: 0.57.2.dev + seconds_per_case: 38.0 + total_cost: 2.4737 + +- dirname: 2024-09-26-15-54-08--architect-4o-deep-jr-diff + test_cases: 133 + model: gpt-4o + edit_format: architect + commit_hash: 89aa385-dirty + editor_model: deepseek + editor_edit_format: diff + pass_rate_1: 57.1 + pass_rate_2: 74.4 + percent_cases_well_formed: 100.0 + error_outputs: 4 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 192 + lazy_comments: 6 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model gpt-4o + date: 2024-09-26 + versions: 0.57.2.dev + seconds_per_case: 44.0 + total_cost: 2.5498 + +- dirname: 2024-09-26-16-06-39--architect-sonnet-deep-jr-diff + test_cases: 133 + model: claude-3.5-sonnet + edit_format: architect + commit_hash: 89aa385-dirty + editor_model: deepseek + editor_edit_format: diff + pass_rate_1: 61.7 + pass_rate_2: 78.9 + percent_cases_well_formed: 100.0 + error_outputs: 2 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 184 + lazy_comments: 2 + syntax_errors: 9 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-09-26 + versions: 0.57.2.dev + seconds_per_case: 43.2 + total_cost: 2.1488 + +- dirname: 2024-09-27-18-15-32--architect-4omini-4omini + test_cases: 133 + model: gpt-4o-mini + edit_format: architect + commit_hash: 0bd8058-dirty + editor_model: gpt-4o-mini + editor_edit_format: whole + pass_rate_1: 43.6 + pass_rate_2: 60.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 208 + lazy_comments: 2 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model gpt-4o-mini + date: 2024-09-27 + versions: 0.57.2.dev + seconds_per_case: 21.0 + total_cost: 0.1527 + +- dirname: 2024-07-18-18-57-46--gpt-4o-mini-whole + test_cases: 133 + model: gpt-4o-mini + edit_format: whole + commit_hash: d31eef3-dirty + pass_rate_1: 40.6 + pass_rate_2: 55.6 + released: 2024-07-18 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model gpt-4o-mini + date: 2024-07-18 + versions: 0.44.1-dev + seconds_per_case: 7.8 + total_cost: 0.0916 + +- dirname: 2024-09-29-22-35-36--architect-o1preview-o1mini-whole + test_cases: 133 + model: o1-preview + edit_format: architect + commit_hash: 53ca83b + editor_model: o1-mini + editor_edit_format: whole + pass_rate_1: 65.4 + pass_rate_2: 85.0 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 179 + lazy_comments: 4 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model o1-preview + date: 2024-09-29 + versions: 0.58.1.dev + seconds_per_case: 39.7 + total_cost: 36.2078 \ No newline at end of file diff --git a/aider/website/_data/blame.yml b/aider/website/_data/blame.yml index 10d520233..29813934d 100644 --- a/aider/website/_data/blame.yml +++ b/aider/website/_data/blame.yml @@ -1801,8 +1801,8 @@ Paul Gauthier (aider): 113 start_tag: v0.44.0 total_lines: 266 -- aider_percentage: 47.04 - aider_total: 254 +- aider_percentage: 53.3 + aider_total: 339 end_date: '2024-07-29' end_tag: v0.46.0 file_counts: @@ -1853,6 +1853,9 @@ aider/scrape.py: Paul Gauthier: 3 Paul Gauthier (aider): 32 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 11 + Paul Gauthier (aider): 85 benchmark/Dockerfile: Your Name: 1 tests/basic/test_coder.py: @@ -1868,13 +1871,13 @@ Paul Gauthier (aider): 73 grand_total: Charles Joachim: 4 - Paul Gauthier: 209 - Paul Gauthier (aider): 204 + Paul Gauthier: 220 + Paul Gauthier (aider): 289 Your Name: 73 Your Name (aider): 50 start_tag: v0.45.0 - total_lines: 540 -- aider_percentage: 59.12 + total_lines: 636 +- aider_percentage: 57.16 aider_total: 415 end_date: '2024-07-31' end_tag: v0.47.0 @@ -1920,6 +1923,8 @@ Paul Gauthier (aider): 2 aider/utils.py: Paul Gauthier: 7 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 24 docker/Dockerfile: Paul Gauthier: 19 Paul Gauthier (aider): 21 @@ -1944,10 +1949,10 @@ tests/basic/test_repomap.py: Paul Gauthier: 1 grand_total: - Paul Gauthier: 287 + Paul Gauthier: 311 Paul Gauthier (aider): 415 start_tag: v0.46.0 - total_lines: 702 + total_lines: 726 - aider_percentage: 44.44 aider_total: 276 end_date: '2024-08-06' @@ -2011,8 +2016,8 @@ paul-gauthier: 1 start_tag: v0.47.0 total_lines: 621 -- aider_percentage: 61.52 - aider_total: 478 +- aider_percentage: 61.2 + aider_total: 489 end_date: '2024-08-10' end_tag: v0.49.0 file_counts: @@ -2055,6 +2060,9 @@ aider/versioncheck.py: Paul Gauthier: 3 Paul Gauthier (aider): 11 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 11 + Paul Gauthier (aider): 11 docker/Dockerfile: Paul Gauthier: 5 Paul Gauthier (aider): 2 @@ -2075,10 +2083,10 @@ Paul Gauthier: 1 Paul Gauthier (aider): 49 grand_total: - Paul Gauthier: 299 - Paul Gauthier (aider): 478 + Paul Gauthier: 310 + Paul Gauthier (aider): 489 start_tag: v0.48.0 - total_lines: 777 + total_lines: 799 - aider_percentage: 66.05 aider_total: 214 end_date: '2024-08-13' @@ -2135,8 +2143,8 @@ Paul Gauthier (aider): 201 start_tag: v0.49.0 total_lines: 324 -- aider_percentage: 56.25 - aider_total: 450 +- aider_percentage: 52.49 + aider_total: 580 end_date: '2024-08-20' end_tag: v0.51.0 file_counts: @@ -2170,6 +2178,14 @@ Paul Gauthier: 3 aider/utils.py: Paul Gauthier (aider): 6 + aider/website/_includes/code-in-json-benchmark.js: + Paul Gauthier: 101 + Paul Gauthier (aider): 64 + aider/website/_includes/code-in-json-syntax.js: + Paul Gauthier: 73 + Paul Gauthier (aider): 66 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 1 benchmark/benchmark.py: Paul Gauthier: 7 benchmark/over_time.py: @@ -2188,7 +2204,968 @@ Paul Gauthier: 15 Paul Gauthier (aider): 104 grand_total: - Paul Gauthier: 350 - Paul Gauthier (aider): 450 + Paul Gauthier: 525 + Paul Gauthier (aider): 580 start_tag: v0.50.0 - total_lines: 800 + total_lines: 1105 +- aider_percentage: 68.1 + aider_total: 521 + end_date: '2024-08-23' + end_tag: v0.52.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/args.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 6 + aider/coders/base_coder.py: + Paul Gauthier: 88 + Paul Gauthier (aider): 15 + aider/coders/chat_chunks.py: + Paul Gauthier (aider): 53 + aider/coders/editblock_coder.py: + Paul Gauthier: 45 + Paul Gauthier (aider): 68 + aider/coders/wholefile_coder.py: + Paul Gauthier: 1 + aider/commands.py: + Paul Gauthier: 5 + Paul Gauthier (aider): 42 + pcamp: 1 + aider/io.py: + Paul Gauthier: 40 + Paul Gauthier (aider): 41 + aider/main.py: + Paul Gauthier: 2 + aider/models.py: + Paul Gauthier: 30 + aider/repomap.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 5 + aider/utils.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 9 + aider/versioncheck.py: + Paul Gauthier: 2 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 1 + benchmark/benchmark.py: + Paul Gauthier: 1 + scripts/blame.py: + Paul Gauthier: 1 + tests/basic/test_commands.py: + Paul Gauthier (aider): 100 + tests/basic/test_editblock.py: + Paul Gauthier (aider): 1 + tests/basic/test_find_or_blocks.py: + Paul Gauthier: 11 + Paul Gauthier (aider): 106 + tests/basic/test_io.py: + Paul Gauthier (aider): 32 + tests/basic/test_main.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 43 + tests/basic/test_wholefile.py: + Paul Gauthier: 8 + grand_total: + Paul Gauthier: 243 + Paul Gauthier (aider): 521 + pcamp: 1 + start_tag: v0.51.0 + total_lines: 765 +- aider_percentage: 61.4 + aider_total: 455 + end_date: '2024-08-27' + end_tag: v0.53.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/args.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 10 + aider/coders/base_coder.py: + Paul Gauthier: 57 + Paul Gauthier (aider): 18 + aider/coders/chat_chunks.py: + Paul Gauthier (aider): 9 + aider/coders/editblock_coder.py: + Paul Gauthier: 44 + Paul Gauthier (aider): 6 + aider/commands.py: + Paul Gauthier: 19 + aider/history.py: + Paul Gauthier (aider): 3 + aider/io.py: + Paul Gauthier: 44 + Paul Gauthier (aider): 22 + aider/main.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 9 + aider/models.py: + Paul Gauthier: 50 + Paul Gauthier (aider): 21 + aider/repo.py: + Paul Gauthier (aider): 3 + aider/repomap.py: + Paul Gauthier: 5 + Paul Gauthier (aider): 1 + aider/sendchat.py: + Paul Gauthier: 7 + Paul Gauthier (aider): 11 + aider/utils.py: + Paul Gauthier: 12 + Paul Gauthier (aider): 9 + aider/versioncheck.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 10 + scripts/versionbump.py: + Paul Gauthier: 1 + tests/basic/test_commands.py: + Paul Gauthier: 23 + tests/basic/test_editblock.py: + Paul Gauthier: 6 + Paul Gauthier (aider): 26 + tests/basic/test_io.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 66 + tests/basic/test_main.py: + Paul Gauthier: 2 + tests/basic/test_models.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 42 + tests/basic/test_repo.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 8 + tests/basic/test_repomap.py: + Paul Gauthier: 4 + Paul Gauthier (aider): 63 + tests/fixtures/sample-code-base/sample.js: + Paul Gauthier (aider): 50 + tests/fixtures/sample-code-base/sample.py: + Paul Gauthier (aider): 68 + grand_total: + Paul Gauthier: 286 + Paul Gauthier (aider): 455 + start_tag: v0.52.0 + total_lines: 741 +- aider_percentage: 63.75 + aider_total: 204 + end_date: '2024-08-28' + end_tag: v0.54.0 + file_counts: + .github/workflows/docker-build-test.yml: + Paul Gauthier (aider): 1 + .github/workflows/ubuntu-tests.yml: + Paul Gauthier (aider): 1 + .github/workflows/windows-tests.yml: + Paul Gauthier (aider): 1 + aider/__init__.py: + Paul Gauthier: 1 + aider/args.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 12 + aider/coders/base_coder.py: + Paul Gauthier: 25 + Paul Gauthier (aider): 12 + aider/commands.py: + Paul Gauthier: 12 + Paul Gauthier (aider): 4 + aider/io.py: + Paul Gauthier: 28 + aider/main.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 6 + aider/models.py: + Paul Gauthier (aider): 11 + aider/run_cmd.py: + Paul Gauthier (aider): 72 + aider/utils.py: + Paul Gauthier (aider): 15 + aider/versioncheck.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 13 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 1 + tests/basic/test_coder.py: + Paul Gauthier: 36 + Paul Gauthier (aider): 27 + tests/basic/test_io.py: + Paul Gauthier: 4 + tests/basic/test_main.py: + Antti Kaihola: 4 + Paul Gauthier (aider): 29 + tests/scrape/test_scrape.py: + Paul Gauthier: 1 + grand_total: + Antti Kaihola: 4 + Paul Gauthier: 112 + Paul Gauthier (aider): 204 + start_tag: v0.53.0 + total_lines: 320 +- aider_percentage: 52.87 + aider_total: 811 + end_date: '2024-09-04' + end_tag: v0.55.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 4 + Paul Gauthier (aider): 2 + aider/args.py: + Paul Gauthier (aider): 7 + aider/coders/base_coder.py: + Paul Gauthier: 63 + Paul Gauthier (aider): 42 + aider/coders/editblock_coder.py: + Nikolay Sedelnikov: 8 + aider/coders/editblock_func_coder.py: + Antti Kaihola: 2 + aider/coders/search_replace.py: + Paul Gauthier: 2 + aider/coders/wholefile_coder.py: + Paul Gauthier: 16 + aider/commands.py: + Antti Kaihola: 7 + Paul Gauthier: 85 + Paul Gauthier (aider): 27 + aider/format_settings.py: + Paul Gauthier (aider): 26 + aider/gui.py: + Paul Gauthier: 4 + aider/io.py: + Paul Gauthier: 63 + Paul Gauthier (aider): 13 + aider/linter.py: + Paul Gauthier: 5 + aider/llm.py: + Paul Gauthier: 2 + aider/main.py: + Paul Gauthier: 86 + Paul Gauthier (aider): 22 + aider/models.py: + Paul Gauthier: 24 + Paul Gauthier (aider): 2 + aider/repo.py: + Paul Gauthier: 85 + aider/repomap.py: + Paul Gauthier: 32 + Paul Gauthier (aider): 4 + aider/report.py: + Paul Gauthier: 77 + Paul Gauthier (aider): 120 + aider/run_cmd.py: + Paul Gauthier: 17 + Paul Gauthier (aider): 24 + aider/scrape.py: + Paul Gauthier: 7 + Paul Gauthier (aider): 8 + aider/special.py: + Paul Gauthier: 5 + Paul Gauthier (aider): 197 + aider/urls.py: + Paul Gauthier (aider): 1 + aider/utils.py: + Paul Gauthier: 31 + Paul Gauthier (aider): 29 + aider/versioncheck.py: + Paul Gauthier: 32 + Paul Gauthier (aider): 6 + aider/voice.py: + Paul Gauthier: 7 + Paul Gauthier (aider): 9 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 1 + scripts/versionbump.py: + Paul Gauthier: 9 + tests/basic/test_coder.py: + Paul Gauthier: 3 + Paul Gauthier (aider): 105 + tests/basic/test_editblock.py: + Antti Kaihola: 3 + Nikolay Sedelnikov: 37 + tests/basic/test_io.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 15 + tests/basic/test_main.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 10 + tests/basic/test_models.py: + Paul Gauthier (aider): 4 + tests/basic/test_repomap.py: + Paul Gauthier (aider): 42 + tests/basic/test_run_cmd.py: + Paul Gauthier (aider): 11 + tests/basic/test_special.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 74 + tests/scrape/test_scrape.py: + Paul Gauthier (aider): 11 + grand_total: + Antti Kaihola: 12 + Nikolay Sedelnikov: 45 + Paul Gauthier: 666 + Paul Gauthier (aider): 811 + start_tag: v0.54.0 + total_lines: 1534 +- aider_percentage: 55.4 + aider_total: 154 + end_date: '2024-09-09' + end_tag: v0.56.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/args.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 6 + aider/coders/base_coder.py: + Paul Gauthier: 14 + Paul Gauthier (aider): 10 + aider/commands.py: + Paul Gauthier: 8 + Paul Gauthier (aider): 6 + aider/io.py: + Paul Gauthier: 5 + aider/linter.py: + Paul Gauthier: 6 + Paul Gauthier (aider): 4 + fry69: 12 + aider/main.py: + Paul Gauthier: 35 + Paul Gauthier (aider): 48 + aider/models.py: + Paul Gauthier: 2 + fry69: 3 + aider/repo.py: + Paul Gauthier: 16 + aider/repomap.py: + Paul Gauthier: 13 + aider/report.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 20 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 1 + benchmark/benchmark.py: + Paul Gauthier: 1 + tests/basic/test_linter.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 51 + tests/basic/test_main.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 9 + grand_total: + Paul Gauthier: 109 + Paul Gauthier (aider): 154 + fry69: 15 + start_tag: v0.55.0 + total_lines: 278 +- aider_percentage: 70.36 + aider_total: 406 + end_date: '2024-09-21' + end_tag: v0.57.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/args_formatter.py: + Paul Gauthier: 4 + Paul Gauthier (aider): 1 + aider/coders/base_coder.py: + Krazer: 1 + Paul Gauthier: 17 + Paul Gauthier (aider): 2 + aider/coders/chat_chunks.py: + Paul Gauthier: 5 + aider/coders/editblock_coder.py: + Paul Gauthier (aider): 27 + aider/commands.py: + Krazer: 3 + Paul Gauthier: 1 + Paul Gauthier (aider): 34 + aider/io.py: + Krazer: 27 + Paul Gauthier: 8 + Paul Gauthier (aider): 42 + aider/main.py: + Krazer: 2 + Paul Gauthier: 5 + Paul Gauthier (aider): 8 + aider/models.py: + Jay Alammar: 1 + Jay Alammar (aider): 13 + Paul Gauthier: 43 + Paul Gauthier (aider): 46 + aider/repo.py: + Paul Gauthier: 3 + aider/run_cmd.py: + Paul Gauthier: 8 + Paul Gauthier (aider): 33 + aider/sendchat.py: + Paul Gauthier: 3 + aider/utils.py: + Paul Gauthier: 2 + aider/website/docs/leaderboards/index.md: + Anjor Kanekar: 1 + Paul Gauthier: 1 + Paul Gauthier (aider): 12 + benchmark/benchmark.py: + Paul Gauthier: 4 + scripts/issues.py: + Paul Gauthier: 10 + Paul Gauthier (aider): 123 + scripts/versionbump.py: + Paul Gauthier (aider): 8 + tests/basic/test_coder.py: + Paul Gauthier: 1 + tests/basic/test_editblock.py: + Christian Clauss: 2 + tests/basic/test_io.py: + Paul Gauthier (aider): 37 + tests/basic/test_main.py: + Paul Gauthier: 18 + Paul Gauthier (aider): 20 + grand_total: + Anjor Kanekar: 1 + Christian Clauss: 2 + Jay Alammar: 1 + Jay Alammar (aider): 13 + Krazer: 33 + Paul Gauthier: 134 + Paul Gauthier (aider): 393 + start_tag: v0.56.0 + total_lines: 577 +- aider_percentage: 47.95 + aider_total: 712 + end_date: '2024-09-29' + end_tag: v0.58.0 + file_counts: + .github/workflows/docker-build-test.yml: + Paul Gauthier: 1 + Paul Gauthier (aider): 11 + aider/__init__.py: + Paul Gauthier: 1 + aider/args.py: + Paul Gauthier: 8 + Paul Gauthier (aider): 109 + Stein Martin Hustad: 17 + fry69: 2 + aider/coders/__init__.py: + Paul Gauthier: 6 + Paul Gauthier (aider): 2 + aider/coders/architect_coder.py: + Paul Gauthier: 40 + Paul Gauthier (aider): 3 + aider/coders/base_coder.py: + Jonathan Ellis: 1 + Paul Gauthier: 32 + Paul Gauthier (aider): 8 + aider/coders/editor_editblock_coder.py: + Paul Gauthier: 6 + Paul Gauthier (aider): 1 + aider/coders/editor_whole_coder.py: + Paul Gauthier: 7 + aider/coders/wholefile_coder.py: + Paul Gauthier: 2 + aider/commands.py: + Jonathan Ellis: 1 + Mike Bailey: 1 + Paul Gauthier: 20 + Paul Gauthier (aider): 78 + fry69: 2 + aider/help.py: + Paul Gauthier: 27 + Paul Gauthier (aider): 7 + aider/history.py: + Paul Gauthier: 1 + aider/io.py: + Paul Gauthier: 39 + Paul Gauthier (aider): 62 + Stein Martin Hustad: 5 + fry69: 10 + aider/linter.py: + Paul Gauthier: 6 + aider/main.py: + Paul Gauthier: 13 + Paul Gauthier (aider): 6 + Stein Martin Hustad: 4 + fry69: 1 + rti: 1 + aider/models.py: + Paul Gauthier: 58 + Paul Gauthier (aider): 85 + aider/repo.py: + Paul Gauthier: 16 + Paul Gauthier (aider): 2 + aider/repomap.py: + Paul Gauthier: 5 + aider/scrape.py: + Paul Gauthier (aider): 3 + aider/sendchat.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 5 + aider/utils.py: + Paul Gauthier: 4 + aider/versioncheck.py: + Paul Gauthier: 2 + aider/voice.py: + Mike Bailey: 17 + Paul Gauthier: 2 + Paul Gauthier (aider): 10 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 153 + benchmark/benchmark.py: + Paul Gauthier: 25 + Paul Gauthier (aider): 29 + fry69: 3 + scripts/issues.py: + Paul Gauthier: 5 + Paul Gauthier (aider): 45 + scripts/update-docs.sh: + Paul Gauthier: 1 + scripts/yank-old-versions.py: + Paul Gauthier (aider): 51 + tests/basic/test_commands.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 98 + tests/basic/test_io.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 97 + tests/basic/test_main.py: + Paul Gauthier: 2 + tests/basic/test_models.py: + Paul Gauthier: 4 + tests/basic/test_sanity_check_repo.py: + fry69: 179 + tests/basic/test_wholefile.py: + Paul Gauthier: 38 + grand_total: + Jonathan Ellis: 2 + Mike Bailey: 18 + Paul Gauthier: 529 + Paul Gauthier (aider): 712 + Stein Martin Hustad: 26 + fry69: 197 + rti: 1 + start_tag: v0.57.0 + total_lines: 1485 +- aider_percentage: 75.44 + aider_total: 172 + end_date: '2024-10-04' + end_tag: v0.59.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/args.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 6 + aider/args_formatter.py: + Paul Gauthier: 4 + aider/coders/architect_coder.py: + Paul Gauthier: 1 + aider/coders/base_coder.py: + Paul Gauthier: 6 + aider/coders/editblock_coder.py: + Paul Gauthier: 1 + aider/commands.py: + Paul Gauthier: 3 + Paul Gauthier (aider): 49 + aider/gui.py: + Paul Gauthier: 2 + aider/main.py: + Paul Gauthier: 10 + Paul Gauthier (aider): 4 + aider/models.py: + Paul Gauthier (aider): 12 + aider/repomap.py: + Paul Gauthier: 9 + Paul Gauthier (aider): 3 + aider/urls.py: + Paul Gauthier: 2 + aider/versioncheck.py: + Paul Gauthier: 1 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 4 + scripts/issues.py: + Paul Gauthier: 1 + scripts/update-docs.sh: + Paul Gauthier: 2 + tests/basic/test_commands.py: + Paul Gauthier: 4 + Paul Gauthier (aider): 80 + tests/basic/test_models.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 18 + tests/basic/test_sanity_check_repo.py: + Paul Gauthier: 1 + tests/help/test_help.py: + Paul Gauthier: 1 + grand_total: + Paul Gauthier: 56 + Paul Gauthier (aider): 172 + start_tag: v0.58.0 + total_lines: 228 +- aider_percentage: 48.95 + aider_total: 140 + end_date: '2024-10-22' + end_tag: v0.60.0 + file_counts: + .github/workflows/close-stale.yml: + Paul Gauthier: 5 + Paul Gauthier (aider): 19 + .github/workflows/pages.yml: + Paul Gauthier: 3 + aider/__init__.py: + Paul Gauthier: 1 + aider/args.py: + Paul Gauthier: 1 + fry69: 2 + aider/coders/base_coder.py: + Paul Gauthier: 2 + aider/coders/editblock_coder.py: + Paul Gauthier (aider): 3 + aider/commands.py: + Paul Gauthier: 1 + aider/help.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 33 + aider/io.py: + Jonathan Ellis: 10 + Paul Gauthier: 7 + aider/main.py: + Paul Gauthier: 20 + Paul Gauthier (aider): 39 + aider/models.py: + Paul Gauthier: 18 + Sven Grunewaldt: 24 + fry69: 16 + aider/resources/__init__.py: + Paul Gauthier: 3 + aider/sendchat.py: + Paul Gauthier: 3 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 1 + tests/basic/test_editblock.py: + Paul Gauthier: 23 + tests/basic/test_main.py: + Paul Gauthier: 1 + tests/help/test_help.py: + Paul Gauthier: 4 + Paul Gauthier (aider): 46 + grand_total: + Jonathan Ellis: 10 + Paul Gauthier: 94 + Paul Gauthier (aider): 140 + Sven Grunewaldt: 24 + fry69: 18 + start_tag: v0.59.0 + total_lines: 286 +- aider_percentage: 67.61 + aider_total: 860 + end_date: '2024-11-01' + end_tag: v0.61.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/analytics.py: + Paul Gauthier: 75 + Paul Gauthier (aider): 89 + aider/args.py: + Paul Gauthier: 5 + Paul Gauthier (aider): 29 + aider/coders/base_coder.py: + Paul Gauthier: 56 + Paul Gauthier (aider): 43 + aider/coders/editblock_coder.py: + Paul Gauthier: 14 + aider/commands.py: + Paul Gauthier: 14 + Paul Gauthier (aider): 86 + aider/io.py: + Paul Gauthier: 12 + Paul Gauthier (aider): 32 + aider/linter.py: + Paul Gauthier: 6 + aider/main.py: + Paul Gauthier: 48 + Paul Gauthier (aider): 10 + aider/models.py: + Paul Gauthier: 54 + Paul Gauthier (aider): 63 + kAIto47802: 4 + aider/repomap.py: + Paul Gauthier: 12 + Paul Gauthier (aider): 52 + aider/sendchat.py: + Paul Gauthier: 23 + Paul Gauthier (aider): 23 + aider/urls.py: + Paul Gauthier: 2 + aider/utils.py: + Paul Gauthier (aider): 6 + scripts/issues.py: + Paul Gauthier (aider): 13 + scripts/pip-compile.sh: + Paul Gauthier (aider): 13 + scripts/update-docs.sh: + Paul Gauthier: 1 + Paul Gauthier (aider): 5 + tests/basic/test_analytics.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 99 + tests/basic/test_commands.py: + Konstantin L: 34 + Paul Gauthier: 45 + Paul Gauthier (aider): 267 + tests/basic/test_io.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 4 + tests/basic/test_main.py: + Paul Gauthier (aider): 3 + tests/basic/test_models.py: + Paul Gauthier: 3 + Paul Gauthier (aider): 9 + tests/basic/test_sanity_check_repo.py: + Paul Gauthier (aider): 6 + tests/basic/test_sendchat.py: + Paul Gauthier (aider): 8 + grand_total: + Konstantin L: 34 + Paul Gauthier: 374 + Paul Gauthier (aider): 860 + kAIto47802: 4 + start_tag: v0.60.0 + total_lines: 1272 +- aider_percentage: 82.42 + aider_total: 75 + end_date: '2024-11-04' + end_tag: v0.62.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/args.py: + Paul Gauthier (aider): 14 + aider/coders/editblock_coder.py: + Paul Gauthier: 6 + aider/main.py: + Paul Gauthier (aider): 4 + aider/models.py: + Paul Gauthier: 5 + Paul Gauthier (aider): 45 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 4 + Paul Gauthier (aider): 12 + grand_total: + Paul Gauthier: 16 + Paul Gauthier (aider): 75 + start_tag: v0.61.0 + total_lines: 91 +- aider_percentage: 55.08 + aider_total: 385 + end_date: '2024-11-13' + end_tag: v0.63.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/coders/architect_coder.py: + Paul Gauthier: 3 + aider/coders/base_coder.py: + Paul Gauthier: 42 + Paul Gauthier (aider): 1 + aider/coders/editblock_coder.py: + Paul Gauthier: 4 + aider/commands.py: + Paul Gauthier: 13 + aider/exceptions.py: + Paul Gauthier: 72 + Paul Gauthier (aider): 4 + aider/io.py: + Paul Gauthier: 3 + Paul Gauthier (aider): 23 + aider/main.py: + Paul Gauthier: 9 + Paul Gauthier (aider): 9 + aider/models.py: + Logan Attwood: 29 + Paul Gauthier: 50 + Paul Gauthier (aider): 7 + aider/repo.py: + Paul Gauthier: 7 + aider/repomap.py: + Paul Gauthier: 4 + aider/sendchat.py: + Paul Gauthier: 17 + Paul Gauthier (aider): 4 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 1 + scripts/issues.py: + Paul Gauthier: 4 + Paul Gauthier (aider): 195 + tests/basic/test_coder.py: + Paul Gauthier: 2 + tests/basic/test_commands.py: + Paul Gauthier (aider): 20 + tests/basic/test_editblock.py: + Paul Gauthier: 41 + tests/basic/test_exceptions.py: + Paul Gauthier (aider): 65 + tests/basic/test_main.py: + Paul Gauthier: 1 + tests/basic/test_sanity_check_repo.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 2 + tests/basic/test_sendchat.py: + Paul Gauthier: 8 + Paul Gauthier (aider): 55 + tests/scrape/test_scrape.py: + Paul Gauthier: 1 + grand_total: + Logan Attwood: 29 + Paul Gauthier: 285 + Paul Gauthier (aider): 385 + start_tag: v0.62.0 + total_lines: 699 +- aider_percentage: 73.15 + aider_total: 880 + end_date: '2024-11-21' + end_tag: v0.64.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/analytics.py: + Paul Gauthier: 20 + Paul Gauthier (aider): 21 + aider/args.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 10 + aider/coders/base_coder.py: + Paul Gauthier: 15 + Paul Gauthier (aider): 3 + caetanominuzzo: 1 + aider/commands.py: + Chad Phillips: 4 + Paul Gauthier: 5 + Paul Gauthier (aider): 19 + aider/editor.py: + Chad Phillips: 133 + Paul Gauthier (aider): 13 + aider/exceptions.py: + Paul Gauthier: 5 + aider/help_pats.py: + Paul Gauthier: 1 + aider/io.py: + Chad Phillips: 9 + Paul Gauthier (aider): 41 + mw: 21 + aider/main.py: + Paul Gauthier: 21 + Paul Gauthier (aider): 41 + aider/models.py: + Paul Gauthier: 41 + Paul Gauthier (aider): 33 + aider/repo.py: + Paul Gauthier (aider): 5 + aider/urls.py: + Paul Gauthier: 1 + aider/website/_includes/edit-leaderboard.js: + Paul Gauthier (aider): 97 + aider/website/_includes/quant-chart.js: + Paul Gauthier: 3 + Paul Gauthier (aider): 66 + aider/website/_includes/refactor-leaderboard.js: + Paul Gauthier (aider): 90 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 1 + Paul Gauthier (aider): 10 + aider/website/share/index.md: + Paul Gauthier (aider): 29 + benchmark/over_time.py: + Paul Gauthier: 11 + Paul Gauthier (aider): 162 + scripts/blame.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 2 + scripts/issues.py: + Paul Gauthier: 5 + Paul Gauthier (aider): 12 + scripts/versionbump.py: + Paul Gauthier: 7 + tests/basic/test_analytics.py: + Paul Gauthier: 12 + Paul Gauthier (aider): 30 + tests/basic/test_commands.py: + Paul Gauthier (aider): 4 + tests/basic/test_editor.py: + Paul Gauthier (aider): 129 + tests/basic/test_main.py: + Paul Gauthier (aider): 8 + tests/basic/test_models.py: + Paul Gauthier: 3 + Paul Gauthier (aider): 55 + grand_total: + Chad Phillips: 146 + Paul Gauthier: 155 + Paul Gauthier (aider): 880 + caetanominuzzo: 1 + mw: 21 + start_tag: v0.63.0 + total_lines: 1203 +- aider_percentage: 81.11 + aider_total: 584 + end_date: '2024-11-26' + end_tag: v0.65.0 + file_counts: + aider/__init__.py: + Paul Gauthier: 1 + aider/analytics.py: + Paul Gauthier: 2 + Paul Gauthier (aider): 5 + aider/args.py: + Paul Gauthier (aider): 12 + aider/coders/base_coder.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 31 + aider/commands.py: + Paul Gauthier: 2 + aider/io.py: + Paul Gauthier: 3 + Paul Gauthier (aider): 9 + aider/main.py: + Paul Gauthier: 15 + Paul Gauthier (aider): 19 + aider/models.py: + Paul Gauthier: 9 + Paul Gauthier (aider): 17 + aider/queries/tree-sitter-dart-tags.scm: + malkoG: 91 + aider/urls.py: + Paul Gauthier (aider): 1 + aider/website/_includes/quant-chart.js: + Paul Gauthier (aider): 76 + aider/website/docs/leaderboards/index.md: + Paul Gauthier: 1 + benchmark/benchmark.py: + Paul Gauthier (aider): 10 + benchmark/docker.sh: + Paul Gauthier (aider): 1 + benchmark/over_time.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 157 + scripts/update-docs.sh: + Paul Gauthier: 1 + scripts/update-history.py: + Paul Gauthier: 8 + Paul Gauthier (aider): 64 + tests/basic/test_coder.py: + Paul Gauthier (aider): 81 + tests/basic/test_editor.py: + Paul Gauthier (aider): 16 + tests/basic/test_main.py: + Paul Gauthier: 1 + Paul Gauthier (aider): 42 + tests/basic/test_models.py: + Paul Gauthier (aider): 30 + tests/basic/test_repomap.py: + Paul Gauthier (aider): 13 + grand_total: + Paul Gauthier: 45 + Paul Gauthier (aider): 584 + malkoG: 91 + start_tag: v0.64.0 + total_lines: 720 diff --git a/aider/website/_data/edit_leaderboard.yml b/aider/website/_data/edit_leaderboard.yml index 7aa2e1343..2ab3cee16 100644 --- a/aider/website/_data/edit_leaderboard.yml +++ b/aider/website/_data/edit_leaderboard.yml @@ -1,7 +1,7 @@ - dirname: 2024-05-01-20-05-59--direct-opus-filenames-outside-fence test_cases: 133 model: claude-3-opus-20240229 - released: 2024-02-29 + _released: 2024-02-29 edit_format: diff commit_hash: f4b1797-dirty, f4b1797 pass_rate_1: 53.4 @@ -20,7 +20,7 @@ versions: 0.30.2-dev seconds_per_case: 32.4 total_cost: 13.8395 - + - dirname: 2024-03-06-16-42-00--claude3-sonnet-whole test_cases: 133 model: claude-3-sonnet-20240229 @@ -43,10 +43,11 @@ versions: 0.25.1-dev seconds_per_case: 23.1 total_cost: 0.0000 - + - dirname: 2024-05-03-20-47-24--gemini-1.5-pro-diff-fenced test_cases: 133 - model: gemini-1.5-pro-latest + released: 2024-05-03 + model: gemini-1.5-pro-001 edit_format: diff-fenced commit_hash: 3a48dfb, 5d32dd7 pass_rate_1: 45.9 @@ -88,7 +89,7 @@ versions: 0.33.1-dev seconds_per_case: 6.5 total_cost: 0.5032 - + - dirname: 2023-11-06-21-23-59--gpt-3.5-turbo-0301 test_cases: 133 model: gpt-3.5-turbo-0301 @@ -111,7 +112,7 @@ versions: 0.16.4-dev seconds_per_case: 6.5 total_cost: 0.4822 - + - dirname: 2023-11-07-02-41-07--gpt-3.5-turbo-0613 test_cases: 133 model: gpt-3.5-turbo-0613 @@ -155,7 +156,7 @@ versions: 0.30.2-dev seconds_per_case: 5.3 total_cost: 0.3261 - + - dirname: 2024-01-25-23-37-15--jan-exercism-gpt-4-0125-preview-udiff test_cases: 133 model: gpt-4-0125-preview @@ -178,7 +179,7 @@ versions: 0.22.1-dev seconds_per_case: 44.8 total_cost: 14.6428 - + - dirname: 2024-05-04-15-07-30--redo-gpt-4-0314-diff-reminder-rules test_cases: 133 model: gpt-4-0314 @@ -201,7 +202,7 @@ versions: 0.31.2-dev seconds_per_case: 19.8 total_cost: 16.2689 - + - dirname: 2023-12-16-21-24-28--editblock-gpt-4-0613-actual-main test_cases: 133 model: gpt-4-0613 @@ -228,7 +229,7 @@ - dirname: 2024-05-08-21-16-03--may-gpt-4-1106-preview-udiff test_cases: 133 model: gpt-4-1106-preview - released: 2023-11-06 + released: 2023-11-06 edit_format: udiff commit_hash: 87664dc pass_rate_1: 51.9 @@ -247,7 +248,7 @@ versions: 0.33.1-dev seconds_per_case: 20.4 total_cost: 6.6061 - + - dirname: 2024-05-01-02-09-20--gpt-4-turbo-examples test_cases: 133 model: gpt-4-turbo-2024-04-09 (udiff) @@ -270,11 +271,11 @@ versions: 0.30.2-dev seconds_per_case: 22.8 total_cost: 6.3337 - + - dirname: 2024-05-03-22-24-48--openrouter--llama3-diff-examples-sys-msg test_cases: 132 model: llama3-70b-8192 - released: 2024-04-18 + _released: 2024-04-18 edit_format: diff commit_hash: b5bb453 pass_rate_1: 38.6 @@ -293,11 +294,11 @@ versions: 0.31.2-dev seconds_per_case: 14.5 total_cost: 0.4311 - + - dirname: 2024-05-06-18-31-08--command-r-plus-whole-final test_cases: 133 model: command-r-plus - released: 2024-04-04 + _released: 2024-04-04 edit_format: whole commit_hash: fc3a43e-dirty pass_rate_1: 21.8 @@ -316,34 +317,11 @@ versions: 0.31.2-dev seconds_per_case: 22.9 total_cost: 2.7494 - -- dirname: 2024-05-09-18-57-52--deepseek-chat-v2-diff-reverted-and-helpful-assistant2 - test_cases: 133 - model: DeepSeek Chat V2 (original) - released: 2024-05-06 - edit_format: diff - commit_hash: 80a3f6d - pass_rate_1: 44.4 - pass_rate_2: 60.9 - percent_cases_well_formed: 97.0 - error_outputs: 14 - num_malformed_responses: 4 - user_asks: 2 - lazy_comments: 0 - syntax_errors: 13 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 3 - command: aider --model deepseek/deepseek-chat - date: 2024-05-09 - versions: 0.33.1-dev - seconds_per_case: 86.8 - total_cost: 0.0941 - + - dirname: 2024-05-07-20-32-37--qwen1.5-110b-chat-whole test_cases: 133 model: qwen1.5-110b-chat - released: 2024-02-04 + released: 2024-02-04 edit_format: whole commit_hash: 70b1c0c pass_rate_1: 30.8 @@ -362,7 +340,7 @@ versions: 0.31.2-dev seconds_per_case: 46.9 total_cost: 0.0000 - + - dirname: 2024-05-07-20-57-04--wizardlm-2-8x22b-whole test_cases: 133 model: WizardLM-2 8x22B @@ -433,6 +411,7 @@ - dirname: 2024-06-08-22-37-55--qwen2-72b-instruct-whole test_cases: 133 model: Qwen2 72B Instruct + released: 2024-06-08 edit_format: whole commit_hash: 02c7335-dirty, 1a97498-dirty pass_rate_1: 44.4 @@ -570,7 +549,7 @@ - dirname: 2024-07-04-14-32-08--claude-3.5-sonnet-diff-continue test_cases: 133 - model: claude-3.5-sonnet + model: claude-3.5-sonnet-20240620 edit_format: diff commit_hash: 35f21b5 pass_rate_1: 57.1 @@ -586,12 +565,12 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --sonnet + command: aider --model claude-3.5-sonnet-20240620 date: 2024-07-04 versions: 0.42.1-dev seconds_per_case: 17.6 total_cost: 3.6346 - + - dirname: 2024-07-01-21-41-48--haiku-whole test_cases: 133 model: claude-3-haiku-20240307 @@ -646,7 +625,7 @@ commit_hash: d31eef3-dirty pass_rate_1: 40.6 pass_rate_2: 55.6 - released: 2024-07-18 + _released: 2024-07-18 percent_cases_well_formed: 100.0 error_outputs: 1 num_malformed_responses: 0 @@ -665,7 +644,7 @@ - dirname: 2024-07-19-08-57-13--openrouter-deepseek-chat-v2-0628 test_cases: 133 - model: DeepSeek Chat V2 0628 + model: DeepSeek Chat V2 0628 (deprecated) edit_format: diff commit_hash: 96ff06e-dirty pass_rate_1: 60.9 @@ -694,7 +673,7 @@ commit_hash: f7ce78b-dirty pass_rate_1: 46.6 pass_rate_2: 63.9 - released: 2024-07-23 + _released: 2024-07-23 percent_cases_well_formed: 92.5 error_outputs: 84 num_malformed_responses: 19 @@ -714,6 +693,7 @@ - dirname: 2024-07-24-06-30-29--llama-405b-whole test_cases: 133 model: llama-3.1-405b-instruct (whole) + _released: 2024-07-23 edit_format: whole commit_hash: a362dea-dirty pass_rate_1: 48.9 @@ -721,7 +701,6 @@ percent_cases_well_formed: 100.0 error_outputs: 0 num_malformed_responses: 0 - released: 2024-07-23 num_with_malformed_responses: 0 user_asks: 0 lazy_comments: 0 @@ -737,7 +716,7 @@ - dirname: 2024-07-24-07-10-58--deepseek-coder2-0724-diff-direct test_cases: 133 - model: DeepSeek Coder V2 0724 + model: DeepSeek Coder V2 0724 (deprecated) edit_format: diff commit_hash: 89965bf pass_rate_1: 57.9 @@ -793,7 +772,7 @@ percent_cases_well_formed: 100.0 error_outputs: 27 num_malformed_responses: 0 - released: 2024-07-23 + _released: 2024-07-23 num_with_malformed_responses: 0 user_asks: 23 lazy_comments: 8 @@ -819,7 +798,7 @@ num_malformed_responses: 0 num_with_malformed_responses: 0 user_asks: 0 - released: 2024-07-23 + _released: 2024-07-23 lazy_comments: 0 syntax_errors: 0 indentation_errors: 0 @@ -855,27 +834,1115 @@ seconds_per_case: 6.5 total_cost: 0.0000 -- dirname: 2024-08-14-13-07-12--chatgpt-4o-latest-diff +- dirname: 2024-08-28-07-10-50--gemini-1.5-pro-exp-0827-diff-fenced test_cases: 133 - model: chatgpt-4o-latest - edit_format: diff - commit_hash: b1c3769 - pass_rate_1: 53.4 - pass_rate_2: 69.2 - percent_cases_well_formed: 97.7 - error_outputs: 27 - num_malformed_responses: 5 - num_with_malformed_responses: 3 - user_asks: 7 + model: gemini-1.5-pro-exp-0827 + released: 2024-08-27 + edit_format: diff-fenced + commit_hash: d8adc75 + pass_rate_1: 54.9 + pass_rate_2: 66.9 + percent_cases_well_formed: 94.7 + error_outputs: 112 + num_malformed_responses: 26 + num_with_malformed_responses: 7 + user_asks: 38 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gemini/gemini-1.5-pro-exp-0827 + date: 2024-08-28 + versions: 0.53.1-dev + seconds_per_case: 14.5 + total_cost: 0.0000 + +- dirname: 2024-08-27-19-20-19--gemini-1.5-flash-exp-0827 + test_cases: 133 + model: gemini-1.5-flash-exp-0827 + edit_format: whole + commit_hash: d8adc75 + pass_rate_1: 40.6 + pass_rate_2: 52.6 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 1 + lazy_comments: 3 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model gemini/gemini-1.5-flash-exp-0827 + date: 2024-08-27 + versions: 0.53.1-dev + seconds_per_case: 6.3 + total_cost: 0.0000 + +- dirname: 2024-08-27-19-42-05--gemini-1.5-flash-8b-exp-0827 + test_cases: 133 + model: gemini-1.5-flash-8b-exp-0827 + edit_format: whole + commit_hash: d8adc75 + pass_rate_1: 31.6 + pass_rate_2: 38.3 + percent_cases_well_formed: 100.0 + error_outputs: 12 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 10 + lazy_comments: 250 + syntax_errors: 6 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model gemini/gemini-1.5-flash-8b-exp-0827 + date: 2024-08-27 + versions: 0.53.1-dev + seconds_per_case: 7.2 + total_cost: 0.0000 + +- dirname: 2024-08-30-15-02-05--nous405b-whole + test_cases: 133 + model: nousresearch/hermes-3-llama-3.1-405b + edit_format: whole + commit_hash: 2d9d605 + pass_rate_1: 51.1 + pass_rate_2: 63.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 lazy_comments: 0 syntax_errors: 0 indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 + command: aider --model openrouter/nousresearch/hermes-3-llama-3.1-405b + date: 2024-08-30 + versions: 0.54.8-dev + seconds_per_case: 38.3 + total_cost: 0.0000 + +- dirname: 2024-09-04-16-08-09--yi-coder-9b-whole + test_cases: 133 + model: Yi Coder 9B Chat + edit_format: whole + commit_hash: c4e4967 + pass_rate_1: 46.6 + pass_rate_2: 54.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 9 + lazy_comments: 0 + syntax_errors: 14 + indentation_errors: 2 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model openai/hf:01-ai/Yi-Coder-9B-Chat --openai-api-base https://glhf.chat/api/openai/v1 + date: 2024-09-04 + versions: 0.54.13.dev + seconds_per_case: 8.3 + total_cost: 0.0000 + _released: 2024-09-04 + +- dirname: 2024-09-04-16-17-33--yi-coder-9b-chat-q4_0-whole + test_cases: 133 + model: yi-coder:9b-chat-q4_0 + edit_format: whole + commit_hash: c4e4967 + pass_rate_1: 41.4 + pass_rate_2: 45.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 48 + lazy_comments: 1 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model ollama/yi-coder:9b-chat-q4_0 + date: 2024-09-04 + versions: 0.54.13.dev + seconds_per_case: 125.3 + total_cost: 0.0000 + +- dirname: 2024-09-05-14-50-11--deepseek-sep5-no-shell + test_cases: 133 + released: 2024-09-05 + model: DeepSeek V2.5 + edit_format: diff + commit_hash: 1279c86 + pass_rate_1: 54.9 + pass_rate_2: 72.2 + percent_cases_well_formed: 96.2 + error_outputs: 5 + num_malformed_responses: 5 + num_with_malformed_responses: 5 + user_asks: 4 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --deepseek + date: 2024-09-05 + versions: 0.55.1.dev + seconds_per_case: 49.6 + total_cost: 0.0998 + +- dirname: 2024-09-06-19-55-17--reflection-hyperbolic-whole-output2 + test_cases: 133 + model: Reflection-70B + edit_format: whole + commit_hash: 74631ee-dirty, 2aef59e-dirty + pass_rate_1: 33.1 + pass_rate_2: 42.1 + percent_cases_well_formed: 100.0 + error_outputs: 2 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 10 + lazy_comments: 26 + syntax_errors: 1 + indentation_errors: 3 + exhausted_context_windows: 0 + test_timeouts: 3 + command: (not currently supported) + date: 2024-09-06 + versions: 0.55.1.dev + seconds_per_case: 61.6 + total_cost: 0.0000 + +- dirname: 2024-09-11-15-42-17--command-r-plus-08-2024-whole + test_cases: 133 + model: Command R+ (08-24) + edit_format: whole + commit_hash: b43ed20 + pass_rate_1: 27.1 + pass_rate_2: 38.3 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 7 + lazy_comments: 10 + syntax_errors: 0 + indentation_errors: 3 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model command-r-plus-08-2024 + date: 2024-09-11 + versions: 0.56.1.dev + seconds_per_case: 20.3 + total_cost: 0.0000 + +- dirname: 2024-09-11-15-47-02--command-r-08-2024-whole + test_cases: 133 + model: Command R (08-24) + edit_format: whole + commit_hash: b43ed20-dirty + pass_rate_1: 30.1 + pass_rate_2: 38.3 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 4 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model command-r-08-2024 + date: 2024-09-11 + versions: 0.56.1.dev + seconds_per_case: 7.6 + total_cost: 0.0000 + +- dirname: 2024-09-12-19-57-35--o1-mini-whole + test_cases: 133 + model: o1-mini (whole) + edit_format: whole + commit_hash: 36fa773-dirty, 291b456 + pass_rate_1: 49.6 + pass_rate_2: 70.7 + percent_cases_well_formed: 90.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 17 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model o1-mini + date: 2024-09-12 + versions: 0.56.1.dev + seconds_per_case: 103.0 + total_cost: 5.3725 + +- dirname: 2024-09-21-16-40-56--o1-mini-flex-sr-markers + test_cases: 36 + model: o1-mini + edit_format: diff + commit_hash: 5493654 + pass_rate_1: 50.0 + pass_rate_2: 61.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 3 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model o1-mini + date: 2024-09-21 + versions: 0.56.1.dev + seconds_per_case: 26.7 + total_cost: 2.4226 + +- dirname: 2024-09-21-16-45-11--o1-preview-flex-sr-markers + test_cases: 133 + model: o1-preview + _released: 2024-09-12 + edit_format: diff + commit_hash: 5493654-dirty + pass_rate_1: 57.9 + pass_rate_2: 79.7 + percent_cases_well_formed: 93.2 + error_outputs: 11 + num_malformed_responses: 11 + num_with_malformed_responses: 9 + user_asks: 3 + lazy_comments: 0 + syntax_errors: 10 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model o1-preview + date: 2024-09-21 + versions: 0.56.1.dev + seconds_per_case: 80.9 + total_cost: 63.9190 + +- dirname: 2024-09-19-16-58-29--qwen2.5-coder:7b-instruct-q8_0 + test_cases: 133 + model: qwen2.5-coder:7b-instruct-q8_0 + edit_format: whole + commit_hash: 6f2b064-dirty + pass_rate_1: 45.1 + pass_rate_2: 51.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 4 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model ollama/qwen2.5-coder:7b-instruct-q8_0 + date: 2024-09-19 + versions: 0.56.0 + seconds_per_case: 9.3 + total_cost: 0.0000 + +- dirname: 2024-09-20-20-20-19--qwen-2.5-72b-instruct-diff + test_cases: 133 + model: qwen-2.5-72b-instruct (bf16) + edit_format: diff + commit_hash: 5139594 + pass_rate_1: 53.4 + pass_rate_2: 65.4 + percent_cases_well_formed: 96.2 + error_outputs: 9 + num_malformed_responses: 9 + num_with_malformed_responses: 5 + user_asks: 3 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model openrouter/qwen/qwen-2.5-72b-instruct + date: 2024-09-20 + versions: 0.56.1.dev + seconds_per_case: 39.8 + total_cost: 0.0000 + +- dirname: 2024-09-21-11-56-43--Codestral-22B-v0.1-Q4_K_M.gguf_whole + test_cases: 133 + model: Codestral-22B-v0.1-Q4_K_M + edit_format: whole + commit_hash: 2753ac6-dirty + pass_rate_1: 36.1 + pass_rate_2: 48.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 8 + lazy_comments: 6 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model Codestral-22B-v0.1-Q4_K_M + date: 2024-09-21 + versions: 0.56.1.dev + seconds_per_case: 656.4 + total_cost: 0.9108 + +- dirname: 2024-09-24-16-26-45--gemini-1.5-pro-002-diff-fenced + test_cases: 133 + model: gemini-1.5-pro-002 + released: 2024-09-24 + edit_format: diff-fenced + commit_hash: 6b5fe9b, 3edcd71 + pass_rate_1: 49.6 + pass_rate_2: 65.4 + percent_cases_well_formed: 96.2 + error_outputs: 17 + num_malformed_responses: 17 + num_with_malformed_responses: 5 + user_asks: 3 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model gemini/gemini-1.5-pro-002 + date: 2024-09-24 + versions: 0.57.2.dev + seconds_per_case: 11.6 + total_cost: 2.8166 + +- dirname: 2024-09-24-16-33-23--gemini-1.5-flash-002-whole + test_cases: 133 + model: gemini-1.5-flash-002 + edit_format: whole + commit_hash: 3edcd71 + pass_rate_1: 37.6 + pass_rate_2: 51.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 3 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model gemini/gemini-1.5-flash-002 + date: 2024-09-24 + versions: 0.57.2.dev + seconds_per_case: 5.1 + total_cost: 0.0515 + +- dirname: 2024-09-24-15-18-59--gemini-1.5-flash-8b-exp-0924-whole + test_cases: 133 + model: gemini-1.5-flash-8b-exp-0924 + edit_format: whole + commit_hash: 86faaa6 + pass_rate_1: 33.1 + pass_rate_2: 38.3 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 9 + lazy_comments: 6 + syntax_errors: 8 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gemini/gemini-1.5-flash-8b-exp-0924 + date: 2024-09-24 + versions: 0.57.2.dev + seconds_per_case: 6.6 + total_cost: 0.0000 + +- dirname: 2024-09-28-18-30-20--codestral-whole + test_cases: 133 + model: ollama/codestral + edit_format: whole + commit_hash: 1971285-dirty + pass_rate_1: 33.8 + pass_rate_2: 45.9 + percent_cases_well_formed: 98.5 + error_outputs: 8 + num_malformed_responses: 8 + num_with_malformed_responses: 2 + user_asks: 12 + lazy_comments: 6 + syntax_errors: 5 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model ollama/codestral + date: 2024-09-28 + versions: 0.57.2.dev + seconds_per_case: 67.2 + total_cost: 0.0000 + +- dirname: 2024-09-29-17-51-11--codegeex4-whole-2 + test_cases: 133 + model: ollama/codegeex4 + edit_format: whole + commit_hash: 228ae24 + pass_rate_1: 28.6 + pass_rate_2: 32.3 + percent_cases_well_formed: 97.0 + error_outputs: 20 + num_malformed_responses: 20 + num_with_malformed_responses: 4 + user_asks: 56 + lazy_comments: 5 + syntax_errors: 5 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model ollama/codegeex4 + date: 2024-09-29 + versions: 0.57.2.dev + seconds_per_case: 128.1 + total_cost: 0.0000 + +- dirname: 2024-09-30-00-09-00--wojtek-opencodeinterpreter-6.7b-whole-2 + test_cases: 133 + model: ollama/wojtek/opencodeinterpreter:6.7b + edit_format: whole + commit_hash: 6d586fd + pass_rate_1: 26.3 + pass_rate_2: 30.1 + percent_cases_well_formed: 91.0 + error_outputs: 18 + num_malformed_responses: 18 + num_with_malformed_responses: 12 + user_asks: 79 + lazy_comments: 7 + syntax_errors: 0 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 6 + command: aider --model ollama/wojtek/opencodeinterpreter:6.7b + date: 2024-09-30 + versions: 0.58.1.dev + seconds_per_case: 59.3 + total_cost: 0.0000 + +- dirname: 2024-09-30-03-49-01--mistral-nemo-12b-instruct-2407-q4_K_M-whole-1 + test_cases: 133 + model: ollama/mistral-nemo:12b-instruct-2407-q4_K_M + edit_format: whole + commit_hash: ba4dec8 + pass_rate_1: 22.6 + pass_rate_2: 33.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 53 + lazy_comments: 37 + syntax_errors: 2 + indentation_errors: 2 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model ollama/mistral-nemo:12b-instruct-2407-q4_K_M + date: 2024-09-30 + versions: 0.58.1.dev + seconds_per_case: 34.7 + total_cost: 0.0000 + +- dirname: 2024-09-30-14-09-43--qwen2.5-32b-whole-2 + test_cases: 133 + model: ollama/qwen2.5:32b + edit_format: whole + commit_hash: 765c4cb + pass_rate_1: 44.4 + pass_rate_2: 54.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 9 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model ollama/qwen2.5:32b + date: 2024-09-30 + versions: 0.58.1.dev + seconds_per_case: 134.9 + total_cost: 0.0000 + +- dirname: 2024-09-30-19-35-40--llama3.2-3b-instruct-fp16-whole-1 + test_cases: 133 + model: ollama/llama3.2:3b-instruct-fp16 + edit_format: whole + commit_hash: 3f12290 + pass_rate_1: 20.3 + pass_rate_2: 26.3 + percent_cases_well_formed: 97.0 + error_outputs: 21 + num_malformed_responses: 21 + num_with_malformed_responses: 4 + user_asks: 73 + lazy_comments: 11 + syntax_errors: 1 + indentation_errors: 3 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model ollama/llama3.2:3b-instruct-fp16 + date: 2024-09-30 + versions: 0.58.1.dev + seconds_per_case: 66.6 + total_cost: 0.0000 + +- dirname: 2024-09-30-23-01-24--hermes3-8b-llama3.1-fp16-whole-2 + test_cases: 133 + model: ollama/hermes3:8b-llama3.1-fp16 + edit_format: whole + commit_hash: c5ba4f7 + pass_rate_1: 24.1 + pass_rate_2: 30.1 + percent_cases_well_formed: 98.5 + syntax_errors: 0 + exhausted_context_windows: 0 + command: aider --model ollama/hermes3:8b-llama3.1-fp16 + date: 2024-09-30 + versions: 0.58.1.dev + seconds_per_case: 64.7 + total_cost: 0.0000 + +- dirname: 2024-10-01-02-33-11--mistral-small-whole-1 + test_cases: 133 + model: ollama/mistral-small + edit_format: whole + commit_hash: 8a908fa + pass_rate_1: 30.1 + pass_rate_2: 38.3 + percent_cases_well_formed: 99.2 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + command: aider --model ollama/mistral-small + date: 2024-10-01 + versions: 0.58.1.dev + seconds_per_case: 84.6 + total_cost: 0.0000 + +- dirname: 2024-10-01-07-05-40--yi-coder-9b-chat-fp16-whole-1 + test_cases: 133 + model: ollama/yi-coder:9b-chat-fp16 + edit_format: whole + commit_hash: 52c6632-dirty + pass_rate_1: 39.8 + pass_rate_2: 43.6 + percent_cases_well_formed: 99.2 + lazy_comments: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + command: aider --model ollama/yi-coder:9b-chat-fp16 + date: 2024-10-01 + versions: 0.58.1.dev + seconds_per_case: 63.7 + total_cost: 0.0000 + +- dirname: 2024-10-01-16-50-09--hermes3-whole-4 + test_cases: 133 + model: ollama/hermes3 + edit_format: whole + commit_hash: 415e898 + pass_rate_1: 21.1 + pass_rate_2: 22.6 + percent_cases_well_formed: 98.5 + exhausted_context_windows: 0 + command: aider --model ollama/hermes3 + date: 2024-10-01 + versions: 0.58.1.dev + seconds_per_case: 24.8 + total_cost: 0.0000 + +- dirname: 2024-10-04-16-30-08--chatgpt-4o-latest-diff-oct4 + test_cases: 133 + model: openai/chatgpt-4o-latest + released: 2024-10-04 + edit_format: diff + commit_hash: af10953 + pass_rate_1: 56.4 + pass_rate_2: 72.2 + percent_cases_well_formed: 97.0 + error_outputs: 4 + num_malformed_responses: 4 + num_with_malformed_responses: 4 + user_asks: 21 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 command: aider --model openai/chatgpt-4o-latest - date: 2024-08-14 - released: 2024-08-08 - versions: 0.50.2-dev - seconds_per_case: 26.3 - total_cost: 3.6113 - \ No newline at end of file + date: 2024-10-04 + versions: 0.58.2.dev + seconds_per_case: 23.7 + total_cost: 4.0641 + +- dirname: 2024-10-05-20-03-10--dracarys-glhf-whole + test_cases: 133 + model: Dracarys2-72B-Instruct + edit_format: whole + commit_hash: 04a2cbb + pass_rate_1: 55.6 + pass_rate_2: 66.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: (via glhf.chat) + date: 2024-10-05 + versions: 0.59.2.dev + seconds_per_case: 46.7 + total_cost: 0.0000 + +- dirname: 2024-10-13-21-33-42--grok2-whole + test_cases: 133 + model: Grok-2 + edit_format: whole + commit_hash: 0a497b7 + pass_rate_1: 45.9 + pass_rate_2: 58.6 + percent_cases_well_formed: 98.5 + error_outputs: 7 + num_malformed_responses: 7 + num_with_malformed_responses: 2 + user_asks: 24 + lazy_comments: 4 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/x-ai/grok-2 + date: 2024-10-13 + versions: 0.59.2.dev + seconds_per_case: 34.6 + total_cost: 0.0000 + +- dirname: 2024-10-13-23-58-44--grok2mini-whole + test_cases: 133 + model: Grok-2-mini + edit_format: whole + commit_hash: 0a497b7-dirty, 0a497b7 + pass_rate_1: 40.6 + pass_rate_2: 54.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 8 + lazy_comments: 2 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/x-ai/grok-2-mini + date: 2024-10-13 + versions: 0.59.2.dev + seconds_per_case: 32.1 + total_cost: 0.0000 + +- dirname: 2024-10-16-15-55-37--nemotron-glhf-whole3 + test_cases: 133 + model: Llama-3.1-Nemotron-70B-Instruct-HF + edit_format: whole + commit_hash: 6bb9b25-dirty + pass_rate_1: 36.8 + pass_rate_2: 54.9 + percent_cases_well_formed: 99.2 + error_outputs: 17 + num_malformed_responses: 1 + num_with_malformed_responses: 1 + user_asks: 53 + lazy_comments: 17 + syntax_errors: 1 + indentation_errors: 2 + exhausted_context_windows: 0 + test_timeouts: 3 + command: (via glhf.chat) + date: 2024-10-16 + versions: 0.59.2.dev + seconds_per_case: 64.9 + total_cost: 0.0000 + +- dirname: 2024-10-22-17-45-28--sonnet-1022-diff-fixed-model-settings + test_cases: 133 + model: claude-3-5-sonnet-20241022 + released: 2024-10-22 + edit_format: diff + commit_hash: 3b14eb9 + pass_rate_1: 69.2 + pass_rate_2: 84.2 + percent_cases_well_formed: 99.2 + error_outputs: 1 + num_malformed_responses: 1 + num_with_malformed_responses: 1 + user_asks: 0 + lazy_comments: 1 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model anthropic/claude-3-5-sonnet-20241022 + date: 2024-10-22 + versions: 0.59.2.dev + seconds_per_case: 18.6 + total_cost: 0.0000 + +- dirname: 2024-11-04-19-19-32--haiku35-diff-ex-as-sys-false + test_cases: 133 + model: claude-3-5-haiku-20241022 + released: 2024-10-22 + edit_format: diff + commit_hash: 03bbdb0-dirty + pass_rate_1: 61.7 + pass_rate_2: 75.2 + percent_cases_well_formed: 95.5 + error_outputs: 11 + num_malformed_responses: 11 + num_with_malformed_responses: 6 + user_asks: 1 + lazy_comments: 1 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model anthropic/claude-3-5-haiku-20241022 + date: 2024-11-04 + versions: 0.61.1.dev + seconds_per_case: 18.4 + total_cost: 0.0000 + +- dirname: 2024-11-07-06-15-36--Qwen2.5.1-Coder-7B-Instruct-GGUF:Q8_0-32k-whole + test_cases: 133 + model: ollama/Qwen2.5.1-Coder-7B-Instruct-GGUF:Q8_0-32k + edit_format: whole + commit_hash: e76704e + pass_rate_1: 52.6 + pass_rate_2: 63.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 4 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model ollama/Qwen2.5.1-Coder-7B-Instruct-GGUF:Q8_0-32k + date: 2024-11-07 + versions: 0.59.2.dev + seconds_per_case: 18.2 + total_cost: 0.0000 + +- dirname: 2024-10-29-00-29-09--Qwen2.5-Coder-0.5B-Instruct + test_cases: 133 + model: Qwen2.5-Coder-0.5B-Instruct + edit_format: whole + commit_hash: 58bd375 + pass_rate_1: 14.3 + pass_rate_2: 14.3 + percent_cases_well_formed: 100.0 + error_outputs: 20 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 45 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 20 + test_timeouts: 2 + command: aider --model openai/Qwen2.5-Coder-0.5B-Instruct + date: 2024-10-29 + versions: 0.59.2.dev + seconds_per_case: 16.0 + total_cost: 0.0000 + +- dirname: 2024-11-11-19-37-01--Qwen2.5-Coder-1.5B-Instruct + test_cases: 133 + model: Qwen2.5-Coder-1.5B-Instruct + edit_format: whole + commit_hash: bb5681c + pass_rate_1: 28.6 + pass_rate_2: 31.6 + percent_cases_well_formed: 100.0 + error_outputs: 5 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 13 + lazy_comments: 2 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 5 + test_timeouts: 2 + command: aider --model openai/Qwen2.5-Coder-1.5B-Instruct + date: 2024-11-11 + versions: 0.59.2.dev + seconds_per_case: 27.4 + total_cost: 0.0000 + +- dirname: 2024-11-04-02-25-32--Qwen2.5-Coder-3B-Instruct + test_cases: 133 + model: Qwen2.5-Coder-3B-Instruct + edit_format: whole + commit_hash: 0ba3647 + pass_rate_1: 33.8 + pass_rate_2: 39.1 + percent_cases_well_formed: 100.0 + error_outputs: 4 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 3 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 4 + test_timeouts: 6 + command: aider --model openai/Qwen2.5-Coder-3B-Instruct + date: 2024-11-04 + versions: 0.59.2.dev + seconds_per_case: 18.7 + total_cost: 0.0000 + +- dirname: 2024-10-16-16-20-59--Qwen2.5-Coder-7B-Instruct + test_cases: 133 + model: Qwen2.5-Coder-7B-Instruct + edit_format: whole + commit_hash: 92fe979-dirty + pass_rate_1: 51.9 + pass_rate_2: 57.9 + percent_cases_well_formed: 100.0 + error_outputs: 2 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 2 + test_timeouts: 5 + command: aider --model openai/Qwen2.5-Coder-7B-Instruct + date: 2024-10-16 + versions: 0.59.2.dev + seconds_per_case: 10.5 + total_cost: 0.0000 + +- dirname: 2024-10-29-11-53-39--Qwen2.5-Coder-14B-Instruct + test_cases: 133 + model: Qwen2.5-Coder-14B-Instruct + edit_format: whole + commit_hash: 58bd375 + pass_rate_1: 58.6 + pass_rate_2: 69.2 + percent_cases_well_formed: 100.0 + error_outputs: 3 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 3 + test_timeouts: 0 + command: aider --model openai/Qwen2.5-Coder-14B-Instruct + date: 2024-10-29 + versions: 0.59.2.dev + seconds_per_case: 18.3 + total_cost: 0.0000 + +- dirname: 2024-11-09-11-09-15--Qwen2.5-Coder-32B-Instruct + test_cases: 133 + model: Qwen2.5-Coder-32B-Instruct + released: 2024-11-12 + edit_format: diff + commit_hash: ec9982a + pass_rate_1: 59.4 + pass_rate_2: 71.4 + percent_cases_well_formed: 94.7 + error_outputs: 17 + num_malformed_responses: 17 + num_with_malformed_responses: 7 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model openai/hf:Qwen/Qwen2.5-Coder-32B-Instruct --openai-api-base https://glhf.chat/api/openai/v1 + date: 2024-11-09 + versions: 0.59.2.dev + seconds_per_case: 22.5 + total_cost: 0.0000 + +- dirname: 2024-11-20-14-57-11--mistral-2411-direct-diff + test_cases: 133 + model: Mistral Large (2411) + released: 2024-11-18 + edit_format: diff + commit_hash: dba844c + pass_rate_1: 46.6 + pass_rate_2: 65.4 + percent_cases_well_formed: 96.2 + error_outputs: 8 + num_malformed_responses: 8 + num_with_malformed_responses: 5 + user_asks: 5 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model mistral/mistral-large-latest + date: 2024-11-20 + versions: 0.63.3.dev + seconds_per_case: 24.9 + total_cost: 3.2334 + +- dirname: 2024-11-20-19-28-30--gpt-4o-2024-11-20 + test_cases: 133 + model: gpt-4o-2024-11-20 + released: 2024-11-20 + edit_format: diff + commit_hash: 2ac0776-dirty + pass_rate_1: 58.6 + pass_rate_2: 71.4 + percent_cases_well_formed: 99.2 + error_outputs: 1 + num_malformed_responses: 1 + num_with_malformed_responses: 1 + user_asks: 4 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 5 + command: aider --model openai/gpt-4o-2024-11-20 + date: 2024-11-20 + versions: 0.63.3.dev + seconds_per_case: 6.0 + total_cost: 0.0000 + +- dirname: 2024-09-20-21-47-17--qwen2.5-32b-instruct-q8_0-whole + test_cases: 133 + model: ollama/qwen2.5:32b-instruct-q8_0 + edit_format: whole + commit_hash: 2753ac6 + pass_rate_1: 46.6 + pass_rate_2: 58.6 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model ollama/qwen2.5:32b-instruct-q8_0 + date: 2024-09-20 + versions: 0.56.1.dev + seconds_per_case: 1763.7 + total_cost: 0.0000 + +- dirname: 2024-11-20-15-17-37--qwen25-32b-or-diff + test_cases: 133 + model: openrouter/qwen/qwen-2.5-coder-32b-instruct + edit_format: diff + commit_hash: e917424 + pass_rate_1: 49.6 + pass_rate_2: 65.4 + percent_cases_well_formed: 84.2 + error_outputs: 43 + num_malformed_responses: 31 + num_with_malformed_responses: 21 + user_asks: 43 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 2 + exhausted_context_windows: 12 + test_timeouts: 2 + command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct + date: 2024-11-20 + versions: 0.63.3.dev + seconds_per_case: 40.7 + total_cost: 0.1497 + +- dirname: 2024-11-21-17-46-36--gemini-exp-1121-diff + test_cases: 133 + model: gemini-exp-1121 + released: 2024-11-21 + edit_format: diff + commit_hash: e94961a + pass_rate_1: 46.6 + pass_rate_2: 57.9 + percent_cases_well_formed: 83.5 + error_outputs: 101 + num_malformed_responses: 101 + num_with_malformed_responses: 22 + user_asks: 5 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 2 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model gemini/gemini-exp-1121 + date: 2024-11-21 + versions: 0.63.3.dev + seconds_per_case: 60.3 + total_cost: 0.0000 + +- dirname: 2024-11-15-20-33-31--gemini-exp-1114-diff + test_cases: 133 + model: gemini-exp-1114 + released: 2024-11-14 + edit_format: diff + commit_hash: 0bf17a4 + pass_rate_1: 50.4 + pass_rate_2: 60.9 + percent_cases_well_formed: 85.7 + error_outputs: 70 + num_malformed_responses: 70 + num_with_malformed_responses: 19 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model gemini/gemini-exp-1114 + date: 2024-11-15 + versions: 0.63.2.dev + seconds_per_case: 38.6 \ No newline at end of file diff --git a/aider/website/_data/o1_results.yml b/aider/website/_data/o1_results.yml new file mode 100644 index 000000000..099355e55 --- /dev/null +++ b/aider/website/_data/o1_results.yml @@ -0,0 +1,186 @@ +- dirname: 2024-07-18-18-57-46--gpt-4o-mini-whole + test_cases: 133 + model: gpt-4o-mini (whole) + edit_format: whole + commit_hash: d31eef3-dirty + pass_rate_1: 40.6 + pass_rate_2: 55.6 + released: 2024-07-18 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model gpt-4o-mini + date: 2024-07-18 + versions: 0.44.1-dev + seconds_per_case: 7.8 + total_cost: 0.0916 + +- dirname: 2024-07-04-14-32-08--claude-3.5-sonnet-diff-continue + test_cases: 133 + model: claude-3.5-sonnet (diff) + edit_format: diff + commit_hash: 35f21b5 + pass_rate_1: 57.1 + pass_rate_2: 77.4 + percent_cases_well_formed: 99.2 + error_outputs: 23 + released: 2024-06-20 + num_malformed_responses: 4 + num_with_malformed_responses: 1 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --sonnet + date: 2024-07-04 + versions: 0.42.1-dev + seconds_per_case: 17.6 + total_cost: 3.6346 + +- dirname: 2024-08-06-18-28-39--gpt-4o-2024-08-06-diff-again + test_cases: 133 + model: gpt-4o-2024-08-06 (diff) + edit_format: diff + commit_hash: ed9ed89 + pass_rate_1: 57.1 + pass_rate_2: 71.4 + percent_cases_well_formed: 98.5 + error_outputs: 18 + num_malformed_responses: 2 + num_with_malformed_responses: 2 + user_asks: 10 + lazy_comments: 0 + syntax_errors: 6 + indentation_errors: 2 + exhausted_context_windows: 0 + test_timeouts: 5 + released: 2024-08-06 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-06 + versions: 0.48.1-dev + seconds_per_case: 6.5 + total_cost: 0.0000 + +- dirname: 2024-09-12-19-57-35--o1-mini-whole + test_cases: 133 + model: o1-mini (whole) + edit_format: whole + commit_hash: 36fa773-dirty, 291b456 + pass_rate_1: 49.6 + pass_rate_2: 70.7 + percent_cases_well_formed: 90.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 17 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model o1-mini + date: 2024-09-12 + versions: 0.56.1.dev + seconds_per_case: 103.0 + total_cost: 5.3725 + +- dirname: 2024-09-12-20-56-22--o1-mini-diff + test_cases: 133 + model: o1-mini (diff) + edit_format: diff + commit_hash: 4598a37-dirty, 291b456, 752e823-dirty + pass_rate_1: 45.1 + pass_rate_2: 62.4 + percent_cases_well_formed: 85.7 + error_outputs: 26 + num_malformed_responses: 26 + num_with_malformed_responses: 19 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model o1-mini --edit-format diff + date: 2024-09-12 + versions: 0.56.1.dev + seconds_per_case: 177.7 + total_cost: 11.1071 + +- dirname: 2024-09-05-21-26-49--sonnet-whole-sep5 + test_cases: 133 + model: claude-3.5-sonnet (whole) + edit_format: whole + commit_hash: 8cfdcbd + pass_rate_1: 55.6 + pass_rate_2: 75.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/anthropic/claude-3.5-sonnet --edit-format whole + date: 2024-09-05 + versions: 0.55.1.dev + seconds_per_case: 15.2 + total_cost: 2.3502 + +- dirname: 2024-09-12-22-44-14--o1-preview-diff + test_cases: 133 + model: o1-preview (diff) + edit_format: diff + commit_hash: 72f52bd + pass_rate_1: 56.4 + pass_rate_2: 75.2 + percent_cases_well_formed: 84.2 + error_outputs: 27 + num_malformed_responses: 27 + num_with_malformed_responses: 21 + user_asks: 8 + lazy_comments: 0 + syntax_errors: 7 + indentation_errors: 3 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model o1-preview + date: 2024-09-12 + versions: 0.56.1.dev + seconds_per_case: 95.8 + total_cost: 71.7927 + +- dirname: 2024-09-13-02-13-59--o1-preview-whole + test_cases: 133 + model: o1-preview (whole) + edit_format: whole + commit_hash: 72f52bd-dirty + pass_rate_1: 58.6 + pass_rate_2: 79.7 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model o1-preview + date: 2024-09-13 + versions: 0.56.1.dev + seconds_per_case: 47.4 + total_cost: 38.0612 \ No newline at end of file diff --git a/aider/website/_data/quant.yml b/aider/website/_data/quant.yml new file mode 100644 index 000000000..4d30e297c --- /dev/null +++ b/aider/website/_data/quant.yml @@ -0,0 +1,322 @@ +- dirname: 2024-11-09-11-09-15--Qwen2.5-Coder-32B-Instruct + test_cases: 133 + model: "HuggingFace via GLHF: BF16" + released: 2024-11-12 + edit_format: diff + commit_hash: ec9982a + pass_rate_1: 59.4 + pass_rate_2: 71.4 + percent_cases_well_formed: 94.7 + error_outputs: 17 + num_malformed_responses: 17 + num_with_malformed_responses: 7 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model openai/hf:Qwen/Qwen2.5-Coder-32B-Instruct --openai-api-base https://glhf.chat/api/openai/v1 + date: 2024-11-09 + versions: 0.59.2.dev + seconds_per_case: 22.5 + total_cost: 0.0000 + +- dirname: 2024-11-22-18-56-13--ollama-qwen2.5-coder:32b-instruct-fp16 + test_cases: 132 + model: "Ollama: fp16" + edit_format: diff + commit_hash: f06452c-dirty, 6a0a97c-dirty, 4e9ae16-dirty, 5506d0f-dirty + pass_rate_1: 58.3 + pass_rate_2: 71.4 + percent_cases_well_formed: 90.2 + error_outputs: 27 + num_malformed_responses: 26 + num_with_malformed_responses: 13 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model ollama/qwen2.5-coder:32b-instruct-fp16 + date: 2024-11-22 + versions: 0.64.2.dev + seconds_per_case: 119.6 + total_cost: 0.0000 + +- dirname: 2024-11-22-14-53-26--hyperbolic-qwen25coder32binstruct + test_cases: 133 + model: "Hyperbolic: BF16" + edit_format: diff + commit_hash: f9ef161, 17aef7b-dirty + pass_rate_1: 57.9 + pass_rate_2: 69.2 + percent_cases_well_formed: 91.7 + error_outputs: 30 + num_malformed_responses: 29 + num_with_malformed_responses: 11 + user_asks: 9 + lazy_comments: 0 + syntax_errors: 4 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model openai/Qwen/Qwen2.5-Coder-32B-Instruct --openai-api-base https://api.hyperbolic.xyz/v1/ + date: 2024-11-22 + versions: 0.64.2.dev + seconds_per_case: 33.2 + total_cost: 0.0000 + +- dirname: 2024-11-22-17-53-35--qwen25-coder-32b-Instruct-4bit + test_cases: 133 + model: "mlx-community: 4bit" + edit_format: diff + commit_hash: a16dcab-dirty + pass_rate_1: 60.2 + pass_rate_2: 72.2 + percent_cases_well_formed: 88.7 + error_outputs: 31 + num_malformed_responses: 30 + num_with_malformed_responses: 15 + user_asks: 6 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 1 + test_timeouts: 0 + command: aider --model openai/mlx-community/Qwen2.5-Coder-32B-Instruct-4bit + date: 2024-11-23 + versions: 0.64.2.dev + seconds_per_case: 53.4 + total_cost: 0.0000 + +- dirname: 2024-11-23-15-07-20--qwen25-coder-32b-Instruct-8bit + test_cases: 133 + model: "mlx-community: 8bit" + edit_format: diff + commit_hash: a16dcab-dirty + pass_rate_1: 59.4 + pass_rate_2: 72.2 + percent_cases_well_formed: 92.5 + error_outputs: 20 + num_malformed_responses: 15 + num_with_malformed_responses: 10 + user_asks: 7 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 5 + test_timeouts: 2 + command: aider --model openai/mlx-community/Qwen2.5-Coder-32B-Instruct-8bit + date: 2024-11-23 + versions: 0.64.2.dev + seconds_per_case: 98.4 + total_cost: 0.0000 + +- dirname: 2024-11-24-22-18-18--or-all-or-fixed-blank-messages2 + test_cases: 133 + model: "OpenRouter: multiple" + edit_format: diff + commit_hash: 0c59d32 + pass_rate_1: 57.1 + pass_rate_2: 67.7 + percent_cases_well_formed: 95.5 + error_outputs: 56 + num_malformed_responses: 10 + num_with_malformed_responses: 6 + user_asks: 14 + lazy_comments: 0 + syntax_errors: 6 + indentation_errors: 0 + exhausted_context_windows: 3 + test_timeouts: 1 + command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct + date: 2024-11-24 + versions: 0.64.2.dev + seconds_per_case: 21.2 + total_cost: 0.1420 + +- dirname: 2024-11-23-21-08-53--ollama-qwen2.5-coder:32b-instruct-q4_K_M-8kctx + test_cases: 133 + model: "Ollama: q4_K_M" + edit_format: diff + commit_hash: baa1335-dirty, e63df83-dirty, ff8c1aa-dirty + pass_rate_1: 54.9 + pass_rate_2: 66.9 + percent_cases_well_formed: 94.0 + error_outputs: 21 + num_malformed_responses: 21 + num_with_malformed_responses: 8 + user_asks: 5 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model ollama/qwen2.5-coder:32b-instruct-q4_K_M + date: 2024-11-23 + versions: 0.64.2.dev + seconds_per_case: 35.7 + total_cost: 0.0000 + +- dirname: 2024-11-24-02-23-32--deepinfra-qwen-diff + test_cases: 133 + model: "Deepinfra: BF16" + edit_format: diff + commit_hash: bb78e2f + pass_rate_1: 58.6 + pass_rate_2: 72.2 + percent_cases_well_formed: 94.7 + error_outputs: 15 + num_malformed_responses: 13 + num_with_malformed_responses: 7 + user_asks: 3 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 2 + test_timeouts: 3 + command: aider --model deepinfra/Qwen/Qwen2.5-Coder-32B-Instruct + date: 2024-11-24 + versions: 0.64.2.dev + seconds_per_case: 17.5 + total_cost: 0.0000 + +- dirname: 2024-11-24-04-12-58--fireworks-qwen-diff + test_cases: 133 + model: "Fireworks: unknown" + edit_format: diff + commit_hash: 757eac0 + pass_rate_1: 57.9 + pass_rate_2: 72.2 + percent_cases_well_formed: 94.0 + error_outputs: 23 + num_malformed_responses: 19 + num_with_malformed_responses: 8 + user_asks: 8 + lazy_comments: 0 + syntax_errors: 6 + indentation_errors: 0 + exhausted_context_windows: 4 + test_timeouts: 1 + command: aider --model fireworks_ai/accounts/fireworks/models/qwen2p5-coder-32b-instruct + date: 2024-11-24 + versions: 0.64.2.dev + seconds_per_case: 10.4 + total_cost: 0.5759 + +- dirname: 2024-11-24-02-04-59--ollama-qwen2.5-coder:32b-instruct-q2_K-8kctx + test_cases: 133 + model: "Ollama: q2_K" + edit_format: diff + commit_hash: 757eac0, bb78e2f, 8d0ba40-dirty, 1d09e96 + pass_rate_1: 48.9 + pass_rate_2: 61.7 + percent_cases_well_formed: 91.7 + error_outputs: 32 + num_malformed_responses: 32 + num_with_malformed_responses: 11 + user_asks: 8 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model ollama/qwen2.5-coder:32b-instruct-q2_K + date: 2024-11-24 + versions: 0.64.2.dev + seconds_per_case: 97.8 + total_cost: 0.0000 + +- dirname: 2024-11-24-14-56-49--qwen25-32b-or-fireworks + test_cases: 133 + model: "Fireworks via OpenRouter: unknown" + edit_format: diff + commit_hash: c2f184f + pass_rate_1: 55.6 + pass_rate_2: 67.7 + percent_cases_well_formed: 94.0 + error_outputs: 39 + num_malformed_responses: 24 + num_with_malformed_responses: 8 + user_asks: 13 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 1 + exhausted_context_windows: 7 + test_timeouts: 4 + command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct + date: 2024-11-24 + versions: 0.64.2.dev + seconds_per_case: 16.1 + total_cost: 0.1391 + +- dirname: 2024-11-24-22-03-19--or-hyperbolic-or-fixed-blank-messages2 + test_cases: 133 + model: "Hyperbolic via OpenRouter: BF16" + edit_format: diff + commit_hash: 0c59d32 + pass_rate_1: 55.6 + pass_rate_2: 68.4 + percent_cases_well_formed: 89.5 + error_outputs: 28 + num_malformed_responses: 24 + num_with_malformed_responses: 14 + user_asks: 29 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 4 + test_timeouts: 1 + command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct + date: 2024-11-24 + versions: 0.64.2.dev + seconds_per_case: 41.5 + total_cost: 0.1402 + +- dirname: 2024-11-24-15-00-50--qwen25-32b-or-deepinfra + test_cases: 133 + model: "Deepinfra via OpenRouter: BF16" + edit_format: diff + commit_hash: c2f184f + pass_rate_1: 57.1 + pass_rate_2: 69.9 + percent_cases_well_formed: 89.5 + error_outputs: 35 + num_malformed_responses: 31 + num_with_malformed_responses: 14 + user_asks: 11 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 1 + exhausted_context_windows: 4 + test_timeouts: 1 + command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct + date: 2024-11-24 + versions: 0.64.2.dev + seconds_per_case: 28.5 + total_cost: 0.1390 + +- dirname: 2024-11-26-03-15-06--ollama-qwen2.5-coder:32b-instruct-fp16-2kctx + test_cases: 132 + model: "Ollama: fp16, 2k ctx" + edit_format: diff + commit_hash: 68be6c5-dirty, 554d274, 2ff3a23, 2ff3a23-dirty, 61759f9, dd48b74, 3ebd47d-dirty + pass_rate_1: 43.2 + pass_rate_2: 51.9 + percent_cases_well_formed: 46.2 + error_outputs: 171 + num_malformed_responses: 165 + num_with_malformed_responses: 71 + user_asks: 97 + lazy_comments: 2 + syntax_errors: 4 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: "aider --model ollama/qwen2.5-coder:32b-instruct-fp16 # num_ctx: 2048" + date: 2024-11-26 + versions: 0.64.2.dev,0.65.1.dev + seconds_per_case: 188.6 + total_cost: 0.0000 \ No newline at end of file diff --git a/aider/website/_data/refactor_leaderboard.yml b/aider/website/_data/refactor_leaderboard.yml index 0cb54d39f..a39c5edd1 100644 --- a/aider/website/_data/refactor_leaderboard.yml +++ b/aider/website/_data/refactor_leaderboard.yml @@ -145,7 +145,7 @@ - dirname: 2024-07-01-18-30-33--refac-claude-3.5-sonnet-diff-not-lazy test_cases: 89 - model: claude-3.5-sonnet (diff) + model: claude-3.5-sonnet-20240620 edit_format: diff commit_hash: 7396e38-dirty pass_rate_1: 64.0 @@ -167,7 +167,7 @@ - dirname: 2024-07-24-07-49-39--refac-deepseek-coder-v2-0724 test_cases: 89 - model: DeepSeek Coder V2 0724 + model: DeepSeek Coder V2 0724 (deprecated) edit_format: diff commit_hash: bb6e597 pass_rate_1: 32.6 @@ -208,4 +208,91 @@ versions: 0.48.1-dev seconds_per_case: 16.9 total_cost: 4.0873 - \ No newline at end of file + +- dirname: 2024-09-05-15-19-05--refac-deepseek-v2.5-no-shell + test_cases: 89 + model: DeepSeek Chat V2.5 + edit_format: diff + commit_hash: 1279c86, 1279c86-dirty + pass_rate_1: 31.5 + percent_cases_well_formed: 67.4 + error_outputs: 90 + num_malformed_responses: 88 + num_with_malformed_responses: 29 + user_asks: 8 + lazy_comments: 7 + syntax_errors: 0 + indentation_errors: 6 + exhausted_context_windows: 2 + test_timeouts: 0 + command: aider --deepseek + date: 2024-09-05 + versions: 0.55.1.dev + seconds_per_case: 225.4 + total_cost: 1.0338 + +- dirname: 2024-10-22-19-57-27--refac-openrouter-sonnet-1022 + test_cases: 89 + model: claude-3-5-sonnet-20241022 + edit_format: diff + commit_hash: 4a3e6ef + pass_rate_1: 92.1 + percent_cases_well_formed: 91.0 + error_outputs: 13 + num_malformed_responses: 12 + num_with_malformed_responses: 8 + user_asks: 14 + lazy_comments: 2 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --sonnet + date: 2024-10-22 + versions: 0.60.1.dev + seconds_per_case: 32.5 + total_cost: 8.4644 + +- dirname: 2024-10-22-20-03-10--refac-o1mini + test_cases: 89 + model: o1-mini + edit_format: diff + commit_hash: 4a3e6ef-dirty + pass_rate_1: 44.9 + percent_cases_well_formed: 29.2 + error_outputs: 151 + num_malformed_responses: 150 + num_with_malformed_responses: 63 + user_asks: 28 + lazy_comments: 2 + syntax_errors: 5 + indentation_errors: 4 + exhausted_context_windows: 1 + test_timeouts: 0 + command: aider --model o1-mini + date: 2024-10-22 + versions: 0.60.1.dev + seconds_per_case: 115.3 + total_cost: 29.0492 + +- dirname: 2024-10-22-20-26-36--refac-o1preview + test_cases: 89 + model: o1-preview + edit_format: diff + commit_hash: 4a3e6ef-dirty + pass_rate_1: 75.3 + percent_cases_well_formed: 57.3 + error_outputs: 75 + num_malformed_responses: 74 + num_with_malformed_responses: 38 + user_asks: 19 + lazy_comments: 2 + syntax_errors: 2 + indentation_errors: 3 + exhausted_context_windows: 1 + test_timeouts: 0 + command: aider --model o1-preview + date: 2024-10-22 + versions: 0.60.1.dev + seconds_per_case: 231.7 + total_cost: 120.9850 \ No newline at end of file diff --git a/aider/website/_data/sonnet-fine.yml b/aider/website/_data/sonnet-fine.yml new file mode 100644 index 000000000..31a1d240e --- /dev/null +++ b/aider/website/_data/sonnet-fine.yml @@ -0,0 +1,459 @@ +- dirname: 2024-06-20-15-16-41--claude-3.5-sonnet-diff + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 068609e-dirty + pass_rate_1: 57.9 + pass_rate_2: 74.4 + percent_cases_well_formed: 97.0 + error_outputs: 48 + num_malformed_responses: 11 + num_with_malformed_responses: 4 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-06-20 + versions: 0.38.1-dev + seconds_per_case: 21.6 + total_cost: 0.0000 + +- dirname: 2024-06-24-12-48-43--claude-3.5-sonnet-udiff + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: udiff + commit_hash: 7be08c7 + pass_rate_1: 62.4 + pass_rate_2: 74.4 + percent_cases_well_formed: 100.0 + error_outputs: 10 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 10 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 2 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-06-24 + versions: 0.39.1-dev + seconds_per_case: 14.3 + total_cost: 0.0000 + +- dirname: 2024-06-24-17-44-31--claude-3.5-sonnet-diff-less-chatty + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 0d484e5 + pass_rate_1: 57.9 + pass_rate_2: 74.4 + percent_cases_well_formed: 99.2 + error_outputs: 14 + num_malformed_responses: 3 + num_with_malformed_responses: 1 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-06-24 + versions: 0.39.1-dev + seconds_per_case: 16.0 + total_cost: 0.0000 + +- dirname: 2024-06-24-17-50-46--claude-3.5-sonnet-diff-less-chatty2 + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 3015495 + pass_rate_1: 59.4 + pass_rate_2: 76.7 + percent_cases_well_formed: 99.2 + error_outputs: 5 + num_malformed_responses: 1 + num_with_malformed_responses: 1 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-06-24 + versions: 0.39.1-dev + seconds_per_case: 15.7 + total_cost: 0.0000 + +- dirname: 2024-06-24-17-56-40--claude-3.5-sonnet-diff-less-chatty-sys-examples + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 3015495-dirty + pass_rate_1: 58.6 + pass_rate_2: 75.9 + percent_cases_well_formed: 100.0 + error_outputs: 2 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-06-24 + versions: 0.39.1-dev + seconds_per_case: 15.9 + total_cost: 0.0000 + +- dirname: 2024-07-04-14-32-08--claude-3.5-sonnet-diff-continue + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 35f21b5 + pass_rate_1: 57.1 + pass_rate_2: 77.4 + percent_cases_well_formed: 99.2 + error_outputs: 23 + num_malformed_responses: 4 + num_with_malformed_responses: 1 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-07-04 + versions: 0.42.1-dev + seconds_per_case: 17.6 + total_cost: 3.6346 + +- dirname: 2024-07-06-19-39-59--claude-3.5-sonnet-diff-platform + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: e47c2a9-dirty + pass_rate_1: 57.9 + pass_rate_2: 78.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-07-06 + versions: 0.42.1-dev + seconds_per_case: 14.6 + total_cost: 3.5616 + +- dirname: 2024-07-24-17-11-07--claude-3.5-sonnet-diff-july24 + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 859a13e + pass_rate_1: 59.4 + pass_rate_2: 78.2 + percent_cases_well_formed: 99.2 + error_outputs: 6 + num_malformed_responses: 1 + num_with_malformed_responses: 1 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-07-24 + versions: 0.45.2-dev + seconds_per_case: 16.9 + total_cost: 3.4981 + +- dirname: 2024-07-28-20-23-42--claude-3.5-sonnet-diff-no-reminder + test_cases: 94 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: e799e89-dirty + pass_rate_1: 59.6 + pass_rate_2: 83.0 + percent_cases_well_formed: 98.9 + error_outputs: 12 + num_malformed_responses: 2 + num_with_malformed_responses: 1 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-07-28 + versions: 0.45.2-dev + seconds_per_case: 15.7 + total_cost: 2.4340 + +- dirname: 2024-08-14-00-46-09--claude-3.5-sonnet-diff-no-ipynb-again + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 139f799 + pass_rate_1: 57.9 + pass_rate_2: 75.9 + percent_cases_well_formed: 98.5 + error_outputs: 22 + num_malformed_responses: 5 + num_with_malformed_responses: 2 + user_asks: 249 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-14 + versions: 0.50.1-dev + seconds_per_case: 18.0 + total_cost: 3.7058 + +- dirname: 2024-06-21-00-07-01--claude-3.5-sonnet-do-over + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: fb26174-dirty + pass_rate_1: 59.4 + pass_rate_2: 80.5 + percent_cases_well_formed: 99.2 + error_outputs: 20 + num_malformed_responses: 4 + num_with_malformed_responses: 1 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-06-21 + versions: 0.39.1-dev + seconds_per_case: 18.3 + total_cost: 0.0000 + +- dirname: 2024-06-21-00-18-25--claude-3.5-sonnet-do-over2 + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: fb26174-dirty + pass_rate_1: 58.6 + pass_rate_2: 77.4 + percent_cases_well_formed: 98.5 + error_outputs: 22 + num_malformed_responses: 4 + num_with_malformed_responses: 2 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-06-21 + versions: 0.39.1-dev + seconds_per_case: 17.3 + total_cost: 0.0000 + +- dirname: 2024-06-24-00-09-40--claude-3.5-sonnet-chatty + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: b44c246-dirty + pass_rate_1: 59.4 + pass_rate_2: 75.2 + percent_cases_well_formed: 98.5 + error_outputs: 21 + num_malformed_responses: 5 + num_with_malformed_responses: 2 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-06-24 + versions: 0.39.1-dev + seconds_per_case: 15.7 + total_cost: 0.0000 + +- dirname: 2024-06-24-00-33-35--claude-3.5-sonnet-chatty-do-over + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: bc1dfa3 + pass_rate_1: 58.6 + pass_rate_2: 76.7 + percent_cases_well_formed: 97.7 + error_outputs: 26 + num_malformed_responses: 6 + num_with_malformed_responses: 3 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-06-24 + versions: 0.39.1-dev + seconds_per_case: 16.4 + total_cost: 0.0000 + +- dirname: 2024-08-18-19-57-30--claude-3.5-sonnet-aug18 + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 5099a5c + pass_rate_1: 54.9 + pass_rate_2: 78.9 + percent_cases_well_formed: 97.7 + error_outputs: 47 + num_malformed_responses: 11 + num_with_malformed_responses: 3 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-18 + versions: 0.50.2-dev + seconds_per_case: 22.3 + total_cost: 3.9008 + +- dirname: 2024-08-18-20-23-50--claude-3.5-sonnet-aug18-cache-prompts + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 53db8cf-dirty + pass_rate_1: 56.4 + pass_rate_2: 78.9 + percent_cases_well_formed: 97.7 + error_outputs: 16 + num_malformed_responses: 4 + num_with_malformed_responses: 3 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-18 + versions: 0.50.2-dev + seconds_per_case: 21.1 + total_cost: 3.6918 + +- dirname: 2024-08-18-23-11-04--claude-3.5-sonnet-aug18-cache-prompts-cold + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 53db8cf-dirty + pass_rate_1: 56.4 + pass_rate_2: 78.2 + percent_cases_well_formed: 97.0 + error_outputs: 30 + num_malformed_responses: 7 + num_with_malformed_responses: 4 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-18 + versions: 0.50.2-dev + seconds_per_case: 21.8 + total_cost: 3.7858 + +- dirname: 2024-08-21-01-07-39--sonnet-diff-cache + test_cases: 133 + model: claude-3-5-sonnet-20240620 + edit_format: diff + commit_hash: e12157b-dirty + pass_rate_1: 57.1 + pass_rate_2: 82.0 + percent_cases_well_formed: 98.5 + error_outputs: 12 + num_malformed_responses: 2 + num_with_malformed_responses: 2 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model claude-3-5-sonnet-20240620 + date: 2024-08-21 + versions: 0.51.2-dev + seconds_per_case: 14.5 + total_cost: 3.1795 + +- dirname: 2024-08-21-00-50-49--shell-cmds-sonnet-user-remind + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 919ea05 + pass_rate_1: 63.2 + pass_rate_2: 79.7 + percent_cases_well_formed: 98.5 + error_outputs: 18 + num_malformed_responses: 4 + num_with_malformed_responses: 2 + user_asks: 26 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 2 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-21 + versions: 0.51.2-dev + seconds_per_case: 16.3 + total_cost: 3.4738 + +- dirname: 2024-08-21-00-55-30--shell-cmds-sonnet-no-user-remind + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: diff + commit_hash: 5c7707a + pass_rate_1: 63.9 + pass_rate_2: 80.5 + percent_cases_well_formed: 97.7 + error_outputs: 51 + num_malformed_responses: 12 + num_with_malformed_responses: 3 + user_asks: 24 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-21 + versions: 0.51.2-dev + seconds_per_case: 17.7 + total_cost: 3.8990 diff --git a/aider/website/_includes/edit-leaderboard.js b/aider/website/_includes/edit-leaderboard.js new file mode 100644 index 000000000..7aeaac769 --- /dev/null +++ b/aider/website/_includes/edit-leaderboard.js @@ -0,0 +1,97 @@ +document.addEventListener('DOMContentLoaded', function () { + var ctx = document.getElementById('editChart').getContext('2d'); + const HIGHTLIGHT_MODEL = 'no no no no'; + var leaderboardData = { + labels: [], + datasets: [{ + label: 'Percent completed correctly', + data: [], + backgroundColor: function(context) { + const label = context.chart.data.labels[context.dataIndex] || ''; + return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 0.2)' : 'rgba(54, 162, 235, 0.2)'; + }, + borderColor: function(context) { + const label = context.chart.data.labels[context.dataIndex] || ''; + return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 1)' : 'rgba(54, 162, 235, 1)'; + }, + borderWidth: 1 + }] + }; + + var allData = []; + {% for row in edit_sorted %} + allData.push({ + model: '{{ row.model }}', + pass_rate_2: {{ row.pass_rate_2 }}, + percent_cases_well_formed: {{ row.percent_cases_well_formed }} + }); + {% endfor %} + + function updateChart() { + var selectedRows = document.querySelectorAll('tr.selected'); + var showAll = selectedRows.length === 0; + + leaderboardData.labels = []; + leaderboardData.datasets[0].data = []; + + allData.forEach(function(row, index) { + var rowElement = document.getElementById('edit-row-' + index); + if (showAll) { + rowElement.classList.remove('selected'); + } + if (showAll || rowElement.classList.contains('selected')) { + leaderboardData.labels.push(row.model); + leaderboardData.datasets[0].data.push(row.pass_rate_2); + } + }); + + leaderboardChart.update(); + } + + var tableBody = document.querySelector('table tbody'); + allData.forEach(function(row, index) { + var tr = tableBody.children[index]; + tr.id = 'edit-row-' + index; + tr.style.cursor = 'pointer'; + tr.onclick = function() { + this.classList.toggle('selected'); + updateChart(); + }; + }); + + var leaderboardChart = new Chart(ctx, { + type: 'bar', + data: leaderboardData, + options: { + scales: { + y: { + beginAtZero: true + } + } + } + }); + + updateChart(); + + // Add search functionality for edit table + document.getElementById('editSearchInput').addEventListener('keyup', function() { + var searchWords = this.value.toLowerCase().split(' ').filter(word => word.length > 0); + var tableBody = document.querySelector('table:first-of-type tbody'); + var rows = tableBody.getElementsByTagName('tr'); + + leaderboardData.labels = []; + leaderboardData.datasets[0].data = []; + + for (var i = 0; i < rows.length; i++) { + var rowText = rows[i].textContent; + if (searchWords.every(word => rowText.toLowerCase().includes(word))) { + rows[i].style.display = ''; + leaderboardData.labels.push(allData[i].model); + leaderboardData.datasets[0].data.push(allData[i].pass_rate_2); + } else { + rows[i].style.display = 'none'; + } + } + leaderboardChart.update(); + }); +}); diff --git a/aider/website/_includes/get-started.md b/aider/website/_includes/get-started.md index 15a873e3a..7fabb5cbd 100644 --- a/aider/website/_includes/get-started.md +++ b/aider/website/_includes/get-started.md @@ -2,7 +2,7 @@ You can get started quickly like this: ``` -python -m pip install aider-chat +python -m pip install -U aider-chat # Change directory into a git repo cd /to/your/git/repo diff --git a/aider/website/_includes/help.md b/aider/website/_includes/help.md index 3071e2c17..661af1043 100644 --- a/aider/website/_includes/help.md +++ b/aider/website/_includes/help.md @@ -1,5 +1,5 @@ If you need more help, please check our -[GitHub issues](https://github.com/paul-gauthier/aider/issues) +[GitHub issues](https://github.com/Aider-AI/aider/issues) and file a new issue if your problem isn't discussed. Or drop into our [Discord](https://discord.gg/Tv2uQnR88V) diff --git a/aider/website/_includes/leaderboard.js b/aider/website/_includes/leaderboard.js new file mode 100644 index 000000000..e69de29bb diff --git a/aider/website/_includes/leaderboard_graph.html b/aider/website/_includes/leaderboard_graph.html new file mode 100644 index 000000000..a862103c7 --- /dev/null +++ b/aider/website/_includes/leaderboard_graph.html @@ -0,0 +1,170 @@ + + diff --git a/aider/website/_includes/multi-line.md b/aider/website/_includes/multi-line.md index 910d50407..5a93562ca 100644 --- a/aider/website/_includes/multi-line.md +++ b/aider/website/_includes/multi-line.md @@ -1,4 +1,19 @@ You can send long, multi-line messages in the chat in a few ways: - Paste a multi-line message directly into the chat. - Enter `{` alone on the first line to start a multiline message and `}` alone on the last line to end it. + - Or, start with `{tag` (where "tag" is any sequence of letters/numbers) and end with `tag}`. This is useful when you need to include closing braces `}` in your message. - Use Meta-ENTER to start a new line without sending the message (Esc+ENTER in some environments). + - Use `/paste` to paste text from the clipboard into the chat. + - Use the `/editor` command to open your editor to create the next chat message. See [editor configuration docs](/docs/config/editor.html) for more info. + +Example with a tag: +``` +{python +def hello(): + print("Hello}") # Note: contains a brace +python} +``` + +{: .note } +People often ask for SHIFT-ENTER to be a soft-newline. +Unfortunately there is no portable way to detect that keystroke in terminals. diff --git a/aider/website/_includes/nav_footer_custom.html b/aider/website/_includes/nav_footer_custom.html index 0afaad722..7c15832fa 100644 --- a/aider/website/_includes/nav_footer_custom.html +++ b/aider/website/_includes/nav_footer_custom.html @@ -1,7 +1,7 @@ diff --git a/aider/website/_includes/quant-chart.js b/aider/website/_includes/quant-chart.js new file mode 100644 index 000000000..fa48d554d --- /dev/null +++ b/aider/website/_includes/quant-chart.js @@ -0,0 +1,95 @@ +document.addEventListener('DOMContentLoaded', function () { + var ctx = document.getElementById('quantChart').getContext('2d'); + var allData = []; + {% for row in site.data.quant %} + allData.push({ + model: '{{ row.model }}', + pass_rate_2: {{ row.pass_rate_2 }} + }); + {% endfor %} + + // Sort data by pass_rate_2 in descending order + allData.sort((a, b) => b.pass_rate_2 - a.pass_rate_2); + + var chart; + + function updateChart(filterText) { + var filteredData = allData.filter(row => + row.model.toLowerCase().includes(filterText.toLowerCase()) + ); + + var chartData = { + labels: filteredData.map(row => row.model), + datasets: [{ + label: 'Percent completed correctly', + data: filteredData.map(row => row.pass_rate_2), + backgroundColor: 'rgba(54, 162, 235, 0.2)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1 + }] + }; + + if (chart) { + chart.data = chartData; + chart.update(); + } else { + chart = new Chart(ctx, { + type: 'bar', + data: chartData, + options: { + plugins: { + legend: { + display: false + }, + title: { + display: true, + text: 'Aider code editing benchmark', + font: { + size: 16 + } + } + }, + scales: { + y: { + beginAtZero: true, + title: { + display: true, + text: 'Percent completed correctly', + font: { + size: 14 + } + }, + ticks: { + font: { + size: 16 + } + } + }, + x: { + ticks: { + font: { + size: 16 + } + }, + title: { + display: true, + text: 'Provider: quantization', + font: { + size: 14 + } + } + } + } + } + }); + } + } + + // Initial chart render + updateChart(''); + + // Connect search input to chart filtering + document.getElementById('quantSearchInput').addEventListener('keyup', function() { + updateChart(this.value); + }); +}); diff --git a/aider/website/_includes/refactor-leaderboard.js b/aider/website/_includes/refactor-leaderboard.js new file mode 100644 index 000000000..d540bde65 --- /dev/null +++ b/aider/website/_includes/refactor-leaderboard.js @@ -0,0 +1,90 @@ +document.addEventListener('DOMContentLoaded', function () { + var ctx = document.getElementById('refacChart').getContext('2d'); + var leaderboardData = { + labels: [], + datasets: [{ + label: 'Percent completed correctly', + data: [], + backgroundColor: 'rgba(54, 162, 235, 0.2)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1 + }] + }; + + var allData = []; + {% for row in refac_sorted %} + allData.push({ + model: '{{ row.model }}', + pass_rate_1: {{ row.pass_rate_1 }}, + percent_cases_well_formed: {{ row.percent_cases_well_formed }} + }); + {% endfor %} + + function updateChart() { + var selectedRows = document.querySelectorAll('tr.selected'); + var showAll = selectedRows.length === 0; + + leaderboardData.labels = []; + leaderboardData.datasets[0].data = []; + + allData.forEach(function(row, index) { + var rowElement = document.getElementById('refac-row-' + index); + if (showAll) { + rowElement.classList.remove('selected'); + } + if (showAll || rowElement.classList.contains('selected')) { + leaderboardData.labels.push(row.model); + leaderboardData.datasets[0].data.push(row.pass_rate_1); + } + }); + + leaderboardChart.update(); + } + + var tableBody = document.querySelectorAll('table tbody')[1]; + allData.forEach(function(row, index) { + var tr = tableBody.children[index]; + tr.id = 'refac-row-' + index; + tr.style.cursor = 'pointer'; + tr.onclick = function() { + this.classList.toggle('selected'); + updateChart(); + }; + }); + + var leaderboardChart = new Chart(ctx, { + type: 'bar', + data: leaderboardData, + options: { + scales: { + y: { + beginAtZero: true + } + } + } + }); + + updateChart(); + + // Add search functionality for refactoring table + document.getElementById('refacSearchInput').addEventListener('keyup', function() { + var searchWords = this.value.toLowerCase().split(' ').filter(word => word.length > 0); + var tableBody = document.querySelectorAll('table tbody')[1]; + var rows = tableBody.getElementsByTagName('tr'); + + leaderboardData.labels = []; + leaderboardData.datasets[0].data = []; + + for (var i = 0; i < rows.length; i++) { + var rowText = rows[i].textContent; + if (searchWords.every(word => rowText.toLowerCase().includes(word))) { + rows[i].style.display = ''; + leaderboardData.labels.push(allData[i].model); + leaderboardData.datasets[0].data.push(allData[i].pass_rate_1); + } else { + rows[i].style.display = 'none'; + } + } + leaderboardChart.update(); + }); +}); diff --git a/aider/website/_includes/replit-pipx.md b/aider/website/_includes/replit-pipx.md new file mode 100644 index 000000000..12ca93f11 --- /dev/null +++ b/aider/website/_includes/replit-pipx.md @@ -0,0 +1,9 @@ +To use aider with pipx on replit, you can run these commands in the replit shell: + +``` +pip install pipx +pipx run aider-chat ...normal aider args... +``` + +If you install aider with pipx on replit and try and run it as just `aider` it will crash with a missing `libstdc++.so.6` library. + diff --git a/aider/website/_posts/2023-10-22-repomap.md b/aider/website/_posts/2023-10-22-repomap.md index 13073a448..0c09d00eb 100644 --- a/aider/website/_posts/2023-10-22-repomap.md +++ b/aider/website/_posts/2023-10-22-repomap.md @@ -110,9 +110,9 @@ source code, by including the critical lines of code for each definition. Here's a sample of the map of the aider repo, just showing the maps of -[base_coder.py](https://github.com/paul-gauthier/aider/blob/main/aider/coders/base_coder.py) +[base_coder.py](https://github.com/Aider-AI/aider/blob/main/aider/coders/base_coder.py) and -[commands.py](https://github.com/paul-gauthier/aider/blob/main/aider/commands.py) +[commands.py](https://github.com/Aider-AI/aider/blob/main/aider/commands.py) : ``` @@ -188,7 +188,7 @@ It specifically uses the [py-tree-sitter-languages](https://github.com/grantjenks/py-tree-sitter-languages) python module, which provides simple, pip-installable binary wheels for -[most popular programming languages](https://github.com/paul-gauthier/grep-ast/blob/main/grep_ast/parsers.py). +[most popular programming languages](https://github.com/Aider-AI/grep-ast/blob/main/grep_ast/parsers.py). Tree-sitter parses source code into an Abstract Syntax Tree (AST) based on the syntax of the programming language. @@ -209,7 +209,7 @@ that aider originally used. Switching from ctags to tree-sitter provides a bunch of benefits: - The map is richer, showing full function call signatures and other details straight from the source files. -- Thanks to `py-tree-sitter-languages`, we get full support for many programming languages via a python package that's automatically installed as part of the normal `python -m pip install aider-chat`. +- Thanks to `py-tree-sitter-languages`, we get full support for many programming languages via a python package that's automatically installed as part of the normal `python -m pip install -U aider-chat`. - We remove the requirement for users to manually install `universal-ctags` via some external tool or package manager (brew, apt, choco, etc). - Tree-sitter integration is a key enabler for future work and capabilities for aider. @@ -245,7 +245,7 @@ just install [aider](https://aider.chat/docs/install.html). ## Credits Aider uses -[modified versions of the tags.scm files](https://github.com/paul-gauthier/aider/tree/main/aider/queries) +[modified versions of the tags.scm files](https://github.com/Aider-AI/aider/tree/main/aider/queries) from these open source tree-sitter language implementations: diff --git a/aider/website/_posts/2024-03-08-claude-3.md b/aider/website/_posts/2024-03-08-claude-3.md index e20e68e32..84b6ff355 100644 --- a/aider/website/_posts/2024-03-08-claude-3.md +++ b/aider/website/_posts/2024-03-08-claude-3.md @@ -23,14 +23,14 @@ making it the best available model for pair programming with AI. To use Claude 3 Opus with aider: ``` -python -m pip install aider-chat +python -m pip install -U aider-chat export ANTHROPIC_API_KEY=sk-... aider --opus ``` ## Aider's code editing benchmark -[Aider](https://github.com/paul-gauthier/aider) +[Aider](https://github.com/Aider-AI/aider) is an open source command line chat tool that lets you pair program with AI on code in your local git repo. diff --git a/aider/website/_posts/2024-04-09-gpt-4-turbo.md b/aider/website/_posts/2024-04-09-gpt-4-turbo.md index abdfb753c..c055b7dac 100644 --- a/aider/website/_posts/2024-04-09-gpt-4-turbo.md +++ b/aider/website/_posts/2024-04-09-gpt-4-turbo.md @@ -52,7 +52,7 @@ def some_complex_method(foo, bar): # ... implement method here ... ``` -Aider uses a ["laziness" benchmark suite](https://github.com/paul-gauthier/refactor-benchmark) +Aider uses a ["laziness" benchmark suite](https://github.com/Aider-AI/refactor-benchmark) which is designed to both provoke and quantify lazy coding. It consists of 89 python refactoring tasks diff --git a/aider/website/_posts/2024-05-02-browser.md b/aider/website/_posts/2024-05-02-browser.md index bb6a90df4..8eca20ed2 100644 --- a/aider/website/_posts/2024-05-02-browser.md +++ b/aider/website/_posts/2024-05-02-browser.md @@ -46,7 +46,7 @@ It also supports [connecting to almost any LLM](https://aider.chat/docs/llms.htm Use the `--browser` switch to launch the browser version of aider: ``` -python -m pip install aider-chat +python -m pip install -U aider-chat export OPENAI_API_KEY= # Mac/Linux setx OPENAI_API_KEY # Windows, restart shell after setx diff --git a/aider/website/_posts/2024-05-13-models-over-time.md b/aider/website/_posts/2024-05-13-models-over-time.md index 3a6b5fa53..7b2bbdf3e 100644 --- a/aider/website/_posts/2024-05-13-models-over-time.md +++ b/aider/website/_posts/2024-05-13-models-over-time.md @@ -15,7 +15,7 @@ nav_exclude: true I recently wanted to draw a graph showing how LLM code editing skill has been changing over time as new models have been released by OpenAI, Anthropic and others. I have all the -[data in a yaml file](https://github.com/paul-gauthier/aider/blob/main/website/_data/edit_leaderboard.yml) that is used to render +[data in a yaml file](https://github.com/Aider-AI/aider/blob/main/website/_data/edit_leaderboard.yml) that is used to render [aider's LLM leaderboards](https://aider.chat/docs/leaderboards/). Below is the aider chat transcript, which shows: diff --git a/aider/website/_posts/2024-05-22-linting.md b/aider/website/_posts/2024-05-22-linting.md index 276c35441..14442a52d 100644 --- a/aider/website/_posts/2024-05-22-linting.md +++ b/aider/website/_posts/2024-05-22-linting.md @@ -25,7 +25,7 @@ This increases the ability of the LLM to understand the problem and make the correct changes to resolve it. Aider ships with basic linters built with tree-sitter that support -[most popular programming languages](https://github.com/paul-gauthier/grep-ast/blob/main/grep_ast/parsers.py). +[most popular programming languages](https://github.com/Aider-AI/grep-ast/blob/main/grep_ast/parsers.py). These built in linters will detect syntax errors and other fatal problems with the code. You can also configure aider to use your preferred linters. diff --git a/aider/website/_posts/2024-05-22-swe-bench-lite.md b/aider/website/_posts/2024-05-22-swe-bench-lite.md index 9659f2a2d..72ccf74d6 100644 --- a/aider/website/_posts/2024-05-22-swe-bench-lite.md +++ b/aider/website/_posts/2024-05-22-swe-bench-lite.md @@ -76,7 +76,7 @@ The held out "acceptance tests" were *only* used after benchmarking to compute statistics on which problems aider correctly resolved. -The [full harness to run aider on SWE Bench Lite is available on GitHub](https://github.com/paul-gauthier/aider-swe-bench). +The [full harness to run aider on SWE Bench Lite is available on GitHub](https://github.com/Aider-AI/aider-swe-bench). The benchmarking process was similar to how a developer might use aider to resolve a GitHub issue: diff --git a/aider/website/_posts/2024-05-24-self-assembly.md b/aider/website/_posts/2024-05-24-self-assembly.md index 2b0f5366a..4ccb9af96 100644 --- a/aider/website/_posts/2024-05-24-self-assembly.md +++ b/aider/website/_posts/2024-05-24-self-assembly.md @@ -12,8 +12,12 @@ nav_exclude: true [![self assembly](/assets/self-assembly.jpg)](https://aider.chat/assets/self-assembly.jpg) +{: .note } +This article is quite out dated. For current statistics, see +[aider's release history](/HISTORY.html). + The -[aider git repo](https://github.com/paul-gauthier/aider) +[aider git repo](https://github.com/Aider-AI/aider) currently contains about 4K commits and 14K lines of code. Aider made 15% of the commits, inserting 4.8K and deleting 1.5K lines of code. diff --git a/aider/website/_posts/2024-06-02-main-swe-bench.md b/aider/website/_posts/2024-06-02-main-swe-bench.md index e164d59b3..72c7b2faa 100644 --- a/aider/website/_posts/2024-06-02-main-swe-bench.md +++ b/aider/website/_posts/2024-06-02-main-swe-bench.md @@ -64,7 +64,7 @@ with the problem statement submitted as the opening chat message from "the user". - After that aider ran as normal, except all of aider's suggestions were always accepted without user approval. -- A [simple harness](https://github.com/paul-gauthier/aider-swe-bench#the-aider-agent) was used to retry the SWE Bench problem if aider produced code that wasn't *plausibly correct*. +- A [simple harness](https://github.com/Aider-AI/aider-swe-bench#the-aider-agent) was used to retry the SWE Bench problem if aider produced code that wasn't *plausibly correct*. Plausibly correct means that aider reported that it had successfully edited the repo without causing syntax errors or breaking any *pre-existing* tests. - If the solution from aider with GPT-4o wasn't plausible, the harness launched aider to try again from scratch using Claude 3 Opus. @@ -90,7 +90,7 @@ For a detailed discussion of the benchmark methodology, see the [article about aider's SWE Bench Lite results](https://aider.chat/2024/05/22/swe-bench-lite.html). Also, the -[aider SWE Bench repository on GitHub](https://github.com/paul-gauthier/aider-swe-bench) +[aider SWE Bench repository on GitHub](https://github.com/Aider-AI/aider-swe-bench) contains the harness and statistics code used for the benchmarks. The benchmarking process was similar to how a developer might use aider to diff --git a/aider/website/_posts/2024-07-01-sonnet-not-lazy.md b/aider/website/_posts/2024-07-01-sonnet-not-lazy.md index 87c96964c..5cb7050e0 100644 --- a/aider/website/_posts/2024-07-01-sonnet-not-lazy.md +++ b/aider/website/_posts/2024-07-01-sonnet-not-lazy.md @@ -37,8 +37,8 @@ Users who tested Sonnet with a preview of [aider's latest release](https://aider.chat/HISTORY.html#aider-v0410) were thrilled: -- *Works like a charm. It is a monster. It refactors files of any size like it is nothing. The continue trick with Sonnet is truly the holy grail. Aider beats [other tools] hands down. I'm going to cancel both subscriptions.* -- [Emasoft](https://github.com/paul-gauthier/aider/issues/705#issuecomment-2200338971) -- *Thanks heaps for this feature - it's a real game changer. I can be more ambitious when asking Claude for larger features.* -- [cngarrison](https://github.com/paul-gauthier/aider/issues/705#issuecomment-2196026656) +- *Works like a charm. It is a monster. It refactors files of any size like it is nothing. The continue trick with Sonnet is truly the holy grail. Aider beats [other tools] hands down. I'm going to cancel both subscriptions.* -- [Emasoft](https://github.com/Aider-AI/aider/issues/705#issuecomment-2200338971) +- *Thanks heaps for this feature - it's a real game changer. I can be more ambitious when asking Claude for larger features.* -- [cngarrison](https://github.com/Aider-AI/aider/issues/705#issuecomment-2196026656) - *Fantastic...! It's such an improvement not being constrained by output token length issues. [I refactored] a single JavaScript file into seven smaller files using a single Aider request.* -- [John Galt](https://discord.com/channels/1131200896827654144/1253492379336441907/1256250487934554143) ## Hitting the 4k token output limit @@ -116,7 +116,7 @@ for more details, but you can get started quickly with aider and Sonnet like this: ``` -$ python -m pip install aider-chat +$ python -m pip install -U aider-chat $ export ANTHROPIC_API_KEY= # Mac/Linux $ setx ANTHROPIC_API_KEY # Windows, restart shell after setx diff --git a/aider/website/_posts/2024-07-25-new-models.md b/aider/website/_posts/2024-07-25-new-models.md index 68572d30f..67ffa45c5 100644 --- a/aider/website/_posts/2024-07-25-new-models.md +++ b/aider/website/_posts/2024-07-25-new-models.md @@ -30,7 +30,7 @@ included for scale. You can code with all of these models using aider like this: ``` -$ python -m pip install aider-chat +$ python -m pip install -U aider-chat # Change directory into a git repo to work on $ cd /to/your/git/repo diff --git a/aider/website/_posts/2024-08-26-sonnet-seems-fine.md b/aider/website/_posts/2024-08-26-sonnet-seems-fine.md new file mode 100644 index 000000000..850aa3929 --- /dev/null +++ b/aider/website/_posts/2024-08-26-sonnet-seems-fine.md @@ -0,0 +1,145 @@ +--- +title: Sonnet seems as good as ever +excerpt: Sonnet's score on the aider code editing benchmark has been stable since it launched. +highlight_image: /assets/sonnet-seems-fine.jpg +--- +{% if page.date %} + +{% endif %} + +# Sonnet seems as good as ever + +Recently there has been a lot of speculation that Sonnet has been +dumbed-down, nerfed or is otherwise performing worse. +Sonnet seems as good as ever, when performing the +[aider code editing benchmark](/docs/benchmarks.html#the-benchmark) +via the API. + +Below is a graph showing the performance of Claude 3.5 Sonnet over time. +It shows every clean, comparable benchmark run performed since Sonnet launched. +Benchmarks were performed for various reasons, usually +to evaluate the effects of small changes to aider's system prompts. + +The graph shows variance, but no indication of a noteworthy +degradation. +There is always some variance in benchmark results, typically +/- 2% +between runs with identical prompts. + +It's worth noting that these results would not capture any changes +made to Anthropic web chat's use of Sonnet. + +
+ +
+ + + + + + +> This graph shows the performance of Claude 3.5 Sonnet on +[aider's code editing benchmark](/docs/benchmarks.html#the-benchmark) +> over time. 'Pass Rate 1' represents the initial success rate, while 'Pass Rate 2' shows the success rate after a second attempt with a chance to fix testing errors. +> The +> [aider LLM code editing leaderboard](https://aider.chat/docs/leaderboards/) +> ranks models based on Pass Rate 2. + diff --git a/aider/website/_posts/2024-09-12-o1.md b/aider/website/_posts/2024-09-12-o1.md new file mode 100644 index 000000000..7b44aa679 --- /dev/null +++ b/aider/website/_posts/2024-09-12-o1.md @@ -0,0 +1,116 @@ +--- +title: o1-preview is SOTA on the aider leaderboard +excerpt: Preliminary benchmark results for the new OpenAI o1 models. +nav_exclude: true +--- +{% if page.date %} + +{% endif %} + +# OpenAI o1-preview is SOTA on the aider leaderboard + + + +{% assign edit_sorted = site.data.o1_results | sort: 'pass_rate_2' | reverse %} +{% include leaderboard_graph.html + chart_id="editChart" + data=edit_sorted + row_prefix="edit-row" + pass_rate_key="pass_rate_2" +%} + + +## o1-preview + +OpenAI o1-preview scored 79.7% on aider's code editing benchmark, +a state of the art result. +It achieved this result with the +["whole" edit format](/docs/leaderboards/#notes-on-the-edit-format), +where the LLM returns a full copy of the source code file with changes. + +It is much more practical to use aider's +["diff" edit format](/docs/leaderboards/#notes-on-the-edit-format), +which allows the LLM to return search/replace blocks to +efficiently edit the source code. +This saves significant time and token costs. + +Using the diff edit format the o1-preview model had a strong +benchmark score of 75.2%. +This likely places o1-preview between Sonnet and GPT-4o for practical use, +but at significantly higher cost. + +## o1-mini + +OpenAI o1-mini is priced similarly to GPT-4o and Claude 3.5 Sonnet, +but scored below those models. +It also works best with the whole edit format. + + +## Future work + +The o1-preview model had trouble conforming to aider's diff edit format. +The o1-mini model had trouble conforming to both the whole and diff edit formats. +Aider is extremely permissive and tries hard to accept anything close +to the correct formats. + +It is surprising that such strong models had trouble with +the syntactic requirements of simple text output formats. +It seems likely that aider could optimize its prompts and edit formats to +better harness the o1 models. + + +## Using aider with o1 + +OpenAI's new o1 models are supported in v0.57.0 of aider: + +``` +aider --model o1-mini +aider --model o1-preview +``` + +{: .note } +> These are initial benchmark results for the o1 models, +> based on aider v0.56.1-dev. +> See the [aider leaderboards](/docs/leaderboards/) for up-to-date results +> based on the latest aider releases. + + + + + + + + + + + + + + {% for row in edit_sorted %} + + + + + + + + {% endfor %} + +
ModelPercent completed correctlyPercent using correct edit formatCommandEdit format
{{ row.model }}{{ row.pass_rate_2 }}%{{ row.percent_cases_well_formed }}%{{ row.command }}{{ row.edit_format }}
+ + + diff --git a/aider/website/_posts/2024-09-26-architect.md b/aider/website/_posts/2024-09-26-architect.md new file mode 100644 index 000000000..ddd3ceab3 --- /dev/null +++ b/aider/website/_posts/2024-09-26-architect.md @@ -0,0 +1,418 @@ +--- +title: Separating code reasoning and editing +excerpt: An Architect model describes how to solve the coding problem, and an Editor model translates that into file edits. This Architect/Editor approach produces SOTA benchmark results. +highlight_image: /assets/architect.jpg +draft: false +nav_exclude: true +--- +{% if page.date %} + +{% endif %} + +# Separating code reasoning and editing + +Aider now has experimental support for using two models to complete each coding task: + +- An Architect model is asked to describe how to solve the coding problem. +- An Editor model is given the Architect's solution and asked to produce specific code editing instructions to apply those changes to existing source files. + +Splitting up "code reasoning" and "code editing" in this manner +has produced SOTA results on +[aider's code editing benchmark](/docs/benchmarks.html#the-benchmark). +Using o1-preview as the Architect with either DeepSeek or o1-mini as the +Editor produced the SOTA score of 85%. +Using the Architect/Editor approach +also significantly improved the benchmark scores of many +models, compared to their previous "solo" baseline scores (striped bars). + + + + + + +{% assign sorted_data = site.data.architect | sort: "pass_rate_2" | reverse %} + + + +## Motivation + +This approach was motivated by the release of OpenAI's o1 models. +They are strong at reasoning, but often fail to output properly formatted +code editing instructions. +It helps to instead let them describe the solution +however they prefer and then pass that output to a more traditional LLM. +This second Editor LLM can then interpret the solution description and +produce the code editing instructions needed to update +the existing source code. + +This approach has recently become attractive for aider due to +rapid improvements in the speed and costs of frontier models. +In particular, chaining older LLMs would have been quite slow and +incompatible with aider's goal of providing an interactive, +pair programming AI coding experience. + +## Code reasoning and code editing + +Normally aider asks the model to solve a coding problem in one prompt, +asking the LLM to explain the solution and return +a well formatted series of file edits. +All of [aider's editing formats](/docs/more/edit-formats.html) +require the LLM to return source code edits in a specific text +format, so that aider can process the edits and apply them to the local source files. + +Because this all happens in a single prompt/response round trip to the LLM, +the model has to split its attention between +solving the coding problem and conforming to the edit format. + +The Architect/Editor approach splits this into two inference steps, possibly +using two different LLMs: + +1. Solve the coding problem (Architect). +2. Turn the proposed solution into a series of well formed code edits (Editor). + +The Architect/Editor approach allows the Architect to focus on solving the coding problem +and *describe the solution however comes naturally to it*. +Similarly, the Editor can focus all of its attention on properly formatting the edits +without needing to reason much about how to solve the coding problem. + +We can assign the Architect and Editor roles to LLMs which are well suited to their needs. +Strong reasoning model like o1-preview make excellent Architects, while +the Editor role can be assigned to an appropriate model based on cost, speed +and code editing skill. + +## Results + +The graph above and the table below show the +[aider's code editing benchmark](/docs/benchmarks.html#the-benchmark) +score for various combinations of Architect and Editor models. + + +Some noteworthy observations: + +- Pairing o1-preview as Architect with either Deepseek or o1-mini as Editor sets a SOTA significantly above the previous best score. This result is obtained with the "whole" editing format, requiring the Editor to output a full update copy of each edited source file. Both of these steps are therefore quite slow, so probably not practical for interactive use with aider. +- Pairing OpenAI's o1-preview with Anthropic's Sonnet as the Editor produces the second best result. This is an entirely practical configuration for users able to work with both providers. +- Pairing many models with themselves in the Architect/Editor configuration can provide +significant benefits. +Sonnet, GPT-4o and GPT-4o-mini all scored higher when used as an Architect/Editor pair. +- Deepseek is surprisingly effective as an Editor model. It seems remarkably capable at turning proposed coding solutions into new, updated versions of the source files. Using the efficient "diff" editing format, Deepseek helps all the Architect models except for Sonnet. + +## Try it! + +The development version of aider +has built in defaults to support Architect/Editor coding with +o1-preview, o1-mini, GPT-4o and Claude 3.5 Sonnet. +Run aider with `--architect` or get started quickly like this: + +``` +pip install -U aider-chat + +# Change directory into a git repo +cd /to/your/git/repo + +# Work with Claude 3.5 Sonnet as the Architect and Editor +export ANTHROPIC_API_KEY=your-key-goes-here +aider --sonnet --architect + +# Work with OpenAI models, using gpt-4o as the Editor +export OPENAI_API_KEY=your-key-goes-here +aider --4o --architect +aider --o1-mini --architect +aider --o1-preview --architect +``` + +## More info + +Aider has a number of "chat modes", and "architect" is available as a new chat mode. +The `--architect` switch is a shortcut for `--chat-mode architect`. +For more details, see documentation on +[aider's chat modes](/docs/usage/modes.html). + + +## Full results + +Below are the benchmark results using various models as the Architect, paired with +various models as the Editor. +Each section includes a "baseline" result, +where the model works +by itself in aider's normal "code" editing mode +(not as part of an Architect/Editor configuration). +This "solo" baseline represents the performance previously available when using +this model with aider. + +
+ + + + + + + + + + + {% for group in grouped_data %} + {% assign group_class = forloop.index | modulo: 2 | plus: 1 %} + {% for item in group.items %} + + + + + + + {% endfor %} + {% endfor %} + +
ArchitectEditorEdit FormatPass Rate
{{ item.model }}{% if item.editor_model %}{{ item.editor_model }}{% else %}Baseline{% endif %}{{ item.editor_edit_format | default: item.edit_format }}{{ item.pass_rate_2 }}%
+
diff --git a/aider/website/_posts/2024-11-21-quantization.md b/aider/website/_posts/2024-11-21-quantization.md new file mode 100644 index 000000000..a1d060edd --- /dev/null +++ b/aider/website/_posts/2024-11-21-quantization.md @@ -0,0 +1,178 @@ +--- +title: Details matter with open source models +excerpt: Open source LLMs are becoming very powerful, but pay attention to how you (or your provider) are serving the model. It can affect code editing skill. +highlight_image: /assets/quantization.jpg +draft: false +nav_exclude: true +--- +{% if page.date %} + +{% endif %} + +# Details matter with open source models +{: .no_toc } + +Open source models like Qwen 2.5 32B Instruct are performing very well on +aider's code editing benchmark, rivaling closed source frontier models. + +But pay attention to how your model is being served and quantized, +as it can impact code editing skill. +Open source models are often available at a variety of quantizations, +and can be served with different token limits. +These details matter when working with code. + +The graph and table below compares different versions of the Qwen 2.5 Coder 32B Instruct model, +served both locally and from a variety of cloud providers. + +- The [HuggingFace BF16 weights](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct) served via [glhf.chat](https://glhf.chat). +- [4bit and 8bit quants for mlx](https://t.co/cwX3DYX35D). +- The results from [OpenRouter's mix of providers](https://openrouter.ai/qwen/qwen-2.5-coder-32b-instruct/providers) which serve the model with different levels of quantization. +- Results from individual providers served via OpenRouter and directly to their own APIs. +- Ollama locally serving different quantizations from the [Ollama model library](https://ollama.com/library/qwen2.5-coder:32b-instruct-q4_K_M). + +This benchmarking effort highlighted a number of pitfalls and details which +can have a significant impact on the model's ability to correctly edit code: + +- **Quantization** -- Open source models are often available at dozens of different quantizations. +Most seem to only modestly decrease code editing skill, but stronger quantizations +do have a real impact. +- **Context window** -- Cloud providers can decide how large a context window to accept, +and they often choose differently. Ollama defaults to a tiny 2k context window, +and silently discards data that exceeds it. Such a small window has +catastrophic effects on performance. +- **Output token limits** -- Open source models are often served with wildly +differing output token limits. This has a direct impact on how much code the +model can write or edit in a response. +- **Buggy cloud providers** -- Between Qwen 2.5 Coder 32B Instruct +and DeepSeek V2.5, there were +multiple cloud providers with broken or buggy API endpoints. +They seemed +to be returning result different from expected based on the advertised +quantization and context sizes. +The harm caused to the code editing benchmark varied from serious +to catastrophic. + +The best versions of the model rival GPT-4o, while the worst performing +quantization is more like the older GPT-4 Turbo. +Even an excellent fp16 quantization falls to GPT-3.5 Turbo levels of performance +if run with Ollama's default 2k context window. + + + +### Sections +{: .no_toc } + +- TOC +{:toc} + +## Benchmark results + + + + + + + + + + + + + + + + + + + {% assign quant_sorted = site.data.quant | sort: 'pass_rate_2' | reverse %} + {% for row in quant_sorted %} + + + + + + + + {% endfor %} + +
ModelPercent completed correctlyPercent using correct edit formatCommandEdit format
{{ row.model }}{{ row.pass_rate_2 }}%{{ row.percent_cases_well_formed }}%{{ row.command }}{{ row.edit_format }}
+ + + + + +## Setting Ollama's context window size + +[Ollama uses a 2k context window by default](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-specify-the-context-window-size), +which is very small for working with aider. +Unlike most other LLM servers, Ollama does not throw an error if you submit +a request that exceeds the context window. +Instead, it just silently truncates the request by discarding the "oldest" messages +in the chat to make it fit within the context window. + +Except for the single 2k context result, +all of the Ollama results above were collected with at least an 8k context window. +An 8k window is large enough to attempt all the coding problems in the benchmark. +Aider sets Ollama's context window to 8k by default, starting in aider v0.65.0. + +You can change the Ollama server's context window with a +[`.aider.model.settings.yml` file](https://aider.chat/docs/config/adv-model-settings.html#model-settings) +like this: + +``` +- name: ollama/qwen2.5-coder:32b-instruct-fp16 + extra_params: + num_ctx: 8192 +``` + +## Choosing providers with OpenRouter + +OpenRouter allows you to ignore specific providers in your +[preferences](https://openrouter.ai/settings/preferences). +This can be used to limit your OpenRouter requests to be +served by only your preferred providers. + +## Notes + +This article went through many revisions as I received feedback from +numerous members of the community. +Here are some of the noteworthy learnings and changes: + +- The first version of this article included incorrect Ollama models. +- Earlier Ollama results used the too small default 2k context window, +artificially harming the benchmark results. +- The benchmark results appear to have uncovered a problem in the way +OpenRouter was communicating with Hyperbolic. +They fixed the issue 11/24/24, shortly after it was pointed out. diff --git a/aider/website/assets/architect.jpg b/aider/website/assets/architect.jpg new file mode 100644 index 000000000..5887da12b Binary files /dev/null and b/aider/website/assets/architect.jpg differ diff --git a/aider/website/assets/models-over-time.png b/aider/website/assets/models-over-time.png index eaed94a53..36c9228bd 100644 Binary files a/aider/website/assets/models-over-time.png and b/aider/website/assets/models-over-time.png differ diff --git a/aider/website/assets/models-over-time.svg b/aider/website/assets/models-over-time.svg index 8fd066630..38c226633 100644 --- a/aider/website/assets/models-over-time.svg +++ b/aider/website/assets/models-over-time.svg @@ -1,12 +1,12 @@ - + - 2024-08-15T09:51:56.911643 + 2024-11-22T19:45:27.696738 image/svg+xml @@ -21,8 +21,8 @@ - - - +" style="stroke: #ffa500; stroke-opacity: 0.5"/> - - + + + + - - + + + + + + + + + - - + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + - - + + + + + + + + + + - - + + + + + + + + - - + + + + + + + + + - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -474,12 +578,12 @@ z - + - + @@ -493,12 +597,12 @@ z - + - + @@ -512,12 +616,12 @@ z - + - + @@ -528,9 +632,28 @@ z - + + + + + + + + + + + + + + + + + + + + - + - - - + + + - - - - - - - - - - - - - - - - - - + - - - + + + - - - + + + - + - + - + - - - + + + - + - + + + + + + + + + + + + + + + + + + - + - - - + + + - + - + + + + + + + + + + + + + + + + + + - + - - + + + - + - + - - - - + + + + - - + - + - + - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - + + + - + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + @@ -1931,107 +1853,60 @@ z - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2209,8 +1967,8 @@ z - - + + diff --git a/aider/website/assets/prompt-caching.jpg b/aider/website/assets/prompt-caching.jpg new file mode 100644 index 000000000..662d80591 Binary files /dev/null and b/aider/website/assets/prompt-caching.jpg differ diff --git a/aider/website/assets/quantization.jpg b/aider/website/assets/quantization.jpg new file mode 100644 index 000000000..798c15872 Binary files /dev/null and b/aider/website/assets/quantization.jpg differ diff --git a/aider/website/assets/sample-analytics.jsonl b/aider/website/assets/sample-analytics.jsonl new file mode 100644 index 000000000..bf186ae2a --- /dev/null +++ b/aider/website/assets/sample-analytics.jsonl @@ -0,0 +1,1000 @@ +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732214094} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7539, "completion_tokens": 548, "total_tokens": 8087, "cost": 0.030837000000000003, "total_cost": 0.360738, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732214492} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 8172, "completion_tokens": 261, "total_tokens": 8433, "cost": 0.028430999999999998, "total_cost": 0.389169, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732214517} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732215325} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732215360} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732215363} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9243, "completion_tokens": 507, "total_tokens": 9750, "cost": 0.035334, "total_cost": 0.42450299999999996, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732215394} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732215967} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732215970} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 5749, "completion_tokens": 189, "total_tokens": 5938, "cost": 0.020082000000000003, "total_cost": 0.44458499999999995, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216011} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6064, "completion_tokens": 161, "total_tokens": 6225, "cost": 0.020607, "total_cost": 0.46519199999999994, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216101} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216226} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 4261, "completion_tokens": 246, "total_tokens": 4507, "cost": 0.016473, "total_cost": 0.48166499999999995, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216234} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6639, "completion_tokens": 133, "total_tokens": 6772, "cost": 0.021912, "total_cost": 0.5035769999999999, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216280} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216317} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216365} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 4722, "completion_tokens": 251, "total_tokens": 4973, "cost": 0.017931, "total_cost": 0.521508, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216372} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6949, "completion_tokens": 154, "total_tokens": 7103, "cost": 0.023157, "total_cost": 0.544665, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216426} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6028, "completion_tokens": 169, "total_tokens": 6197, "cost": 0.020619, "total_cost": 0.5652839999999999, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732216439} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732217127} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 43, "total_tokens": 2246, "cost": 0.00040427999999999997, "total_cost": 0.00040427999999999997, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732217130} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732217171} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6292, "completion_tokens": 309, "total_tokens": 6601, "cost": 0.023511, "total_cost": 0.5887949999999998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218000} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218131} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218131} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218564} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218564} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218567} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218756} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218757} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218961} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732218961} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219071} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219072} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219199} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219199} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219202} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219204} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219211} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219229} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219229} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219239} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 6845, "completion_tokens": 0, "total_tokens": 6845, "cost": 0.020535, "total_cost": 0.020535, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219240} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219254} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 6863, "completion_tokens": 0, "total_tokens": 6863, "cost": 0.020589, "total_cost": 0.041124, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219254} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219256} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219262} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219263} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219264} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 6862, "completion_tokens": 389, "total_tokens": 7251, "cost": 0.026421, "total_cost": 0.026421, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219278} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219286} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 7372, "completion_tokens": 291, "total_tokens": 7663, "cost": 0.026481, "total_cost": 0.052902000000000005, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219295} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219308} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 7678, "completion_tokens": 202, "total_tokens": 7880, "cost": 0.026064, "total_cost": 0.07896600000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219316} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219331} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219348} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 6872, "completion_tokens": 235, "total_tokens": 7107, "cost": 0.024141, "total_cost": 0.103107, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219357} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219429} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219429} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219451} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 6973, "completion_tokens": 513, "total_tokens": 7486, "cost": 0.028614, "total_cost": 0.028614, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219466} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219524} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219525} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219538} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219556} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6151, "completion_tokens": 251, "total_tokens": 6402, "cost": 0.022218, "total_cost": 0.022218, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219607} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219616} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219628} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 6671, "completion_tokens": 429, "total_tokens": 7100, "cost": 0.026448, "total_cost": 0.048666, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219640} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732219765} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732220004} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732220004} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732220215} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732220215} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732220642} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732220642} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732221139} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732221215} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732221215} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732221304} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.63.3.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732221304} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732221402} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732221403} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732222469} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732222470} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732222562} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732222562} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.1"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732222680} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.1"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732222681} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732224618} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732224622} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732225984} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732225984} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226083} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226083} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226295} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 3577, "completion_tokens": 1518, "total_tokens": 5095, "cost": 0.033501, "total_cost": 0.033501, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226325} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7097, "completion_tokens": 3651, "total_tokens": 10748, "cost": 0.076056, "total_cost": 0.109557, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226417} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226450} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226494} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226498} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226501} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226513} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 4603, "completion_tokens": 309, "total_tokens": 4912, "cost": 0.018444000000000002, "total_cost": 0.128001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226545} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226579} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226590} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 22736, "completion_tokens": 346, "total_tokens": 23082, "cost": 0.073398, "total_cost": 0.201399, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732226599} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732227043} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732227043} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732227522} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732227522} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732227527} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 4582, "completion_tokens": 118, "total_tokens": 4700, "cost": 0.015516, "total_cost": 0.015516, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732227542} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732227629} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732227629} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732231730} +{"event": "model warning", "properties": {"main_model": "None", "weak_model": "None", "editor_model": "None", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732231732} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732231749} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732231957} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 63, "completion_tokens": 30, "total_tokens": 93, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732231970} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732236291} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732236292} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 4594, "completion_tokens": 173, "total_tokens": 4767, "cost": 0.016377000000000003, "total_cost": 0.016377000000000003, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732236306} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732236484} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242463} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242464} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242471} +{"event": "command_chat-mode", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242472} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 6967, "completion_tokens": 252, "total_tokens": 7219, "cost": 0.024680999999999998, "total_cost": 0.024680999999999998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242510} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 7264, "completion_tokens": 391, "total_tokens": 7655, "cost": 0.027657, "total_cost": 0.052337999999999996, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242684} +{"event": "command_code", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242700} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9810, "completion_tokens": 633, "total_tokens": 10443, "cost": 0.038925, "total_cost": 0.091263, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242715} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242751} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242751} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 8528, "completion_tokens": 208, "total_tokens": 8736, "cost": 0.028704, "total_cost": 0.11996699999999999, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242781} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242784} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242784} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242806} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242806} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242809} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242830} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242830} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242833} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242840} +{"event": "message_send", "properties": {"main_model": "gpt-4o-mini", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o-mini", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 8, "total_tokens": 76, "cost": 1.4999999999999999e-05, "total_cost": 1.4999999999999999e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242841} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242844} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242859} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242934} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732242934} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732243037} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732243038} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732243040} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732243053} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732243054} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732243054} +{"event": "message_send", "properties": {"main_model": "gpt-4o-mini", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o-mini", "edit_format": "whole", "prompt_tokens": 682, "completion_tokens": 39, "total_tokens": 721, "cost": 0.0001257, "total_cost": 0.0001257, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732243061} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732243062} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732243067} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732283822} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732283823} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732287087} +{"event": "model warning", "properties": {"main_model": "openai/REDACTED", "weak_model": "openai/REDACTED", "editor_model": "openai/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732287089} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732287094} +{"event": "message_send", "properties": {"main_model": "openai/REDACTED", "weak_model": "openai/REDACTED", "editor_model": "openai/REDACTED", "edit_format": "diff", "prompt_tokens": 4704, "completion_tokens": 0, "total_tokens": 4704, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732287100} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732287115} +{"event": "message_send", "properties": {"main_model": "openai/REDACTED", "weak_model": "openai/REDACTED", "editor_model": "openai/REDACTED", "edit_format": "diff", "prompt_tokens": 3136, "completion_tokens": 0, "total_tokens": 3136, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732287120} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288494} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288494} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288498} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288506} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6251, "completion_tokens": 320, "total_tokens": 6571, "cost": 0.023552999999999998, "total_cost": 0.023552999999999998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288559} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288568} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288579} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288583} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7008, "completion_tokens": 244, "total_tokens": 7252, "cost": 0.024684, "total_cost": 0.048237, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288598} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288619} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288622} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288623} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6851, "completion_tokens": 762, "total_tokens": 7613, "cost": 0.031983000000000004, "total_cost": 0.08022000000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732288641} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 8559, "completion_tokens": 527, "total_tokens": 9086, "cost": 0.033582, "total_cost": 0.11380200000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732289146} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732290032} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732290034} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 5682, "completion_tokens": 125, "total_tokens": 5807, "cost": 0.018921000000000004, "total_cost": 0.132723, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732290044} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732298794} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732298794} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732298844} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 1470, "completion_tokens": 267, "total_tokens": 1737, "cost": 0.008414999999999999, "total_cost": 0.008414999999999999, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732298851} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 3814, "completion_tokens": 120, "total_tokens": 3934, "cost": 0.013242, "total_cost": 0.021657, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732298865} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301216} +{"event": "model warning", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301218} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 47, "total_tokens": 2250, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301225} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301235} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 47, "total_tokens": 2250, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301240} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301245} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 47, "total_tokens": 2250, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301250} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301280} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 0, "total_tokens": 2203, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301284} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301304} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 47, "total_tokens": 2250, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301309} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301462} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 0, "total_tokens": 2203, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301493} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301495} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 0, "total_tokens": 2203, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301505} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301509} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 0, "total_tokens": 2203, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301523} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301525} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 0, "total_tokens": 2203, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301535} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301537} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 38, "total_tokens": 2241, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301562} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301567} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 129, "total_tokens": 2332, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301589} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301669} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 60, "total_tokens": 2263, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301674} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301684} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 38, "total_tokens": 2241, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732301700} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732302442} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 38, "total_tokens": 2241, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732302454} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732302458} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 102, "total_tokens": 2305, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732302514} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732314005} +{"event": "model warning", "properties": {"main_model": "xai/REDACTED", "weak_model": "xai/REDACTED", "editor_model": "xai/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732314007} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732314019} +{"event": "model warning", "properties": {"main_model": "xai/grok-beta", "weak_model": "xai/grok-beta", "editor_model": "xai/grok-beta", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732314021} +{"event": "cli session", "properties": {"main_model": "xai/grok-beta", "weak_model": "xai/grok-beta", "editor_model": "xai/grok-beta", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732314024} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732314048} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732393998} +{"event": "model warning", "properties": {"main_model": "lm_studio/REDACTED", "weak_model": "lm_studio/REDACTED", "editor_model": "lm_studio/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394000} +{"event": "cli session", "properties": {"main_model": "lm_studio/REDACTED", "weak_model": "lm_studio/REDACTED", "editor_model": "lm_studio/REDACTED", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394003} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394005} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394043} +{"event": "cli session", "properties": {"main_model": "lm_studio/REDACTED", "weak_model": "lm_studio/REDACTED", "editor_model": "lm_studio/REDACTED", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394046} +{"event": "message_send", "properties": {"main_model": "lm_studio/REDACTED", "weak_model": "lm_studio/REDACTED", "editor_model": "lm_studio/REDACTED", "edit_format": "whole", "prompt_tokens": 406, "completion_tokens": 0, "total_tokens": 406, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394050} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394434} +{"event": "model warning", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394436} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394443} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394445} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394476} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394491} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394522} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394524} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 67, "completion_tokens": 24, "total_tokens": 91, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394530} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394534} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 165, "completion_tokens": 17, "total_tokens": 182, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394536} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394581} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394587} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394591} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394596} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394598} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 1856, "completion_tokens": 5, "total_tokens": 1861, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394602} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394605} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394612} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 3584, "completion_tokens": 21, "total_tokens": 3605, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394618} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394625} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 1856, "completion_tokens": 5, "total_tokens": 1861, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394628} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394635} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 2240, "completion_tokens": 21, "total_tokens": 2261, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394639} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394641} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394671} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394673} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394682} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394684} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394708} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394710} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394710} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394720} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394722} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394722} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 2240, "completion_tokens": 0, "total_tokens": 2240, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394732} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394739} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394741} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394742} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 2240, "completion_tokens": 0, "total_tokens": 2240, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394771} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 2257, "completion_tokens": 5, "total_tokens": 2262, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394782} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394796} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394798} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394799} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 4544, "completion_tokens": 33, "total_tokens": 4577, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394806} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394810} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394812} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 3968, "completion_tokens": 5, "total_tokens": 3973, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394817} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394833} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394835} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394837} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 3968, "completion_tokens": 5, "total_tokens": 3973, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394851} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394853} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394858} +{"event": "command_run", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394862} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394865} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394871} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 8000, "completion_tokens": 5, "total_tokens": 8005, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394878} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394885} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394887} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 8576, "completion_tokens": 33, "total_tokens": 8609, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394897} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732394899} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395028} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395030} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395030} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395037} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395046} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395052} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395060} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395068} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395075} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395086} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395089} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395091} +{"event": "command_tokens", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395093} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 64640, "completion_tokens": 5, "total_tokens": 64645, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395332} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395345} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395418} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395420} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395422} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732395439} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732396231} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732396233} +{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 64636, "completion_tokens": 0, "total_tokens": 64636, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732396236} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732399992} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732399993} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732399995} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732399997} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732399997} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400000} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6446, "completion_tokens": 211, "total_tokens": 6657, "cost": 0.022503000000000002, "total_cost": 0.022503000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400049} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400102} +{"event": "command_lint", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400103} +{"event": "command_commit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400107} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400117} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400477} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400478} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400552} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 2110, "completion_tokens": 276, "total_tokens": 2386, "cost": 0.01047, "total_cost": 0.01047, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400560} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 3125, "completion_tokens": 371, "total_tokens": 3496, "cost": 0.01494, "total_cost": 0.025410000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400580} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 5721, "completion_tokens": 520, "total_tokens": 6241, "cost": 0.024963000000000003, "total_cost": 0.050373, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400603} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732400613} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732404392} +{"event": "cli session", "properties": {"main_model": "ollama_chat/REDACTED", "weak_model": "ollama_chat/REDACTED", "editor_model": "ollama_chat/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732404394} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732404395} +{"event": "message_send", "properties": {"main_model": "ollama_chat/REDACTED", "weak_model": "ollama_chat/REDACTED", "editor_model": "ollama_chat/REDACTED", "edit_format": "ask", "prompt_tokens": 63, "completion_tokens": 37, "total_tokens": 100, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732404400} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732404401} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732412885} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732412886} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732412890} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732412894} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732412898} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7040, "completion_tokens": 170, "total_tokens": 7210, "cost": 0.02367, "total_cost": 0.02367, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732412913} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732413619} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732413620} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732413628} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2322, "completion_tokens": 399, "total_tokens": 2721, "cost": 0.012951, "total_cost": 0.012951, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732413736} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732414921} +{"event": "model warning", "properties": {"main_model": "deepinfra/REDACTED", "weak_model": "deepinfra/REDACTED", "editor_model": "deepinfra/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732414923} +{"event": "cli session", "properties": {"main_model": "deepinfra/REDACTED", "weak_model": "deepinfra/REDACTED", "editor_model": "deepinfra/REDACTED", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732414926} +{"event": "message_send", "properties": {"main_model": "deepinfra/REDACTED", "weak_model": "deepinfra/REDACTED", "editor_model": "deepinfra/REDACTED", "edit_format": "diff", "prompt_tokens": 2870, "completion_tokens": 31, "total_tokens": 2901, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732414929} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732414930} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732415453} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2175, "completion_tokens": 86, "total_tokens": 2261, "cost": 0.007815, "total_cost": 0.007815, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732415459} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732415495} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732415544} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732415556} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732415739} +{"event": "message_send", "properties": {"main_model": "openai/REDACTED", "weak_model": "openai/REDACTED", "editor_model": "openai/REDACTED", "edit_format": "diff", "prompt_tokens": 1568, "completion_tokens": 34, "total_tokens": 1602, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732415744} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732421525} +{"event": "model warning", "properties": {"main_model": "fireworks/REDACTED", "weak_model": "fireworks/REDACTED", "editor_model": "fireworks/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732421527} +{"event": "cli session", "properties": {"main_model": "fireworks/REDACTED", "weak_model": "fireworks/REDACTED", "editor_model": "fireworks/REDACTED", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732421528} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732421552} +{"event": "cli session", "properties": {"main_model": "fireworks_ai/accounts/fireworks/models/qwen2p5-coder-32b-instruct", "weak_model": "fireworks_ai/accounts/fireworks/models/qwen2p5-coder-32b-instruct", "editor_model": "fireworks_ai/accounts/fireworks/models/qwen2p5-coder-32b-instruct", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732421554} +{"event": "message_send", "properties": {"main_model": "fireworks_ai/accounts/fireworks/models/qwen2p5-coder-32b-instruct", "weak_model": "fireworks_ai/accounts/fireworks/models/qwen2p5-coder-32b-instruct", "editor_model": "fireworks_ai/accounts/fireworks/models/qwen2p5-coder-32b-instruct", "edit_format": "whole", "prompt_tokens": 593, "completion_tokens": 24, "total_tokens": 617, "cost": 0.0005553, "total_cost": 0.0005553, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732421557} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732460750} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732460751} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732460754} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732460768} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 4075, "completion_tokens": 254, "total_tokens": 4329, "cost": 0.016035, "total_cost": 0.016035, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732460779} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6460, "completion_tokens": 556, "total_tokens": 7016, "cost": 0.02772, "total_cost": 0.043755, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732460798} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732461088} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732461091} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732461104} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 7239, "completion_tokens": 634, "total_tokens": 7873, "cost": 0.031227, "total_cost": 0.07498200000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732461120} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9919, "completion_tokens": 956, "total_tokens": 10875, "cost": 0.044097000000000004, "total_cost": 0.11907900000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732461157} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 8685, "completion_tokens": 151, "total_tokens": 8836, "cost": 0.02832, "total_cost": 0.14739900000000003, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732461193} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732481168} +{"event": "model warning", "properties": {"main_model": "openai/REDACTED", "weak_model": "openai/REDACTED", "editor_model": "openai/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732481170} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732481179} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732481199} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483337} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483388} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483400} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483488} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483509} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 2752, "completion_tokens": 0, "total_tokens": 2752, "cost": 0.00049536, "total_cost": 0.00062892, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483519} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483529} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483542} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483546} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483559} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483578} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483601} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483633} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483677} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483691} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 752, "completion_tokens": 125, "total_tokens": 877, "cost": 0.00015786, "total_cost": 0.00029142, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483695} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483723} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 0, "total_tokens": 2203, "cost": 0.00039653999999999997, "total_cost": 0.00039653999999999997, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483735} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483751} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483764} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 2629, "completion_tokens": 0, "total_tokens": 2629, "cost": 0.00047322, "total_cost": 0.00060678, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483766} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483797} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483833} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483846} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483865} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483878} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483948} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483969} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732483985} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732484014} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732484029} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732484034} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732484052} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732484089} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732484143} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732484158} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732484246} +{"event": "message_send", "properties": {"main_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "weak_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "editor_model": "openrouter/qwen/qwen-2.5-coder-32b-instruct", "edit_format": "diff", "prompt_tokens": 350, "completion_tokens": 392, "total_tokens": 742, "cost": 0.00013356000000000002, "total_cost": 0.00013356000000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732484259} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732490410} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732490416} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 10329, "completion_tokens": 242, "total_tokens": 10571, "cost": 0.034617, "total_cost": 0.034617, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732490434} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 10735, "completion_tokens": 91, "total_tokens": 10826, "cost": 0.033569999999999996, "total_cost": 0.068187, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732490442} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732490681} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732490682} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732493670} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732493734} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732493735} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732496707} +{"event": "cli session", "properties": {"main_model": "ollama_chat/REDACTED", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "ollama_chat/REDACTED", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732496710} +{"event": "message_send", "properties": {"main_model": "ollama_chat/REDACTED", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "ollama_chat/REDACTED", "edit_format": "whole", "prompt_tokens": 593, "completion_tokens": 26, "total_tokens": 619, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732496715} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732496719} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732503219} +{"event": "message_send", "properties": {"main_model": "openrouter/deepseek/deepseek-coder", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "openrouter/deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4519, "completion_tokens": 0, "total_tokens": 4519, "cost": 0.0006326600000000001, "total_cost": 0.0006326600000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732503223} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732503230} +{"event": "message_send", "properties": {"main_model": "openrouter/REDACTED", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "openrouter/REDACTED", "edit_format": "whole", "prompt_tokens": 593, "completion_tokens": 13, "total_tokens": 606, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732503234} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732504520} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732552179} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732552180} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732554412} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732554412} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732556336} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732556337} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732556340} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732556343} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588055} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588056} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588086} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 29685, "completion_tokens": 906, "total_tokens": 30591, "cost": 0.10264500000000001, "total_cost": 0.10264500000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588184} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 31058, "completion_tokens": 102, "total_tokens": 31160, "cost": 0.09470400000000001, "total_cost": 0.19734900000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588194} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 31234, "completion_tokens": 223, "total_tokens": 31457, "cost": 0.09704700000000001, "total_cost": 0.29439600000000005, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588245} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588278} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 29910, "completion_tokens": 357, "total_tokens": 30267, "cost": 0.095085, "total_cost": 0.3894810000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588304} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 30906, "completion_tokens": 221, "total_tokens": 31127, "cost": 0.09603300000000001, "total_cost": 0.4855140000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588338} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588372} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 29683, "completion_tokens": 923, "total_tokens": 30606, "cost": 0.102894, "total_cost": 0.5884080000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588443} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 31065, "completion_tokens": 96, "total_tokens": 31161, "cost": 0.094635, "total_cost": 0.6830430000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588455} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 31303, "completion_tokens": 90, "total_tokens": 31393, "cost": 0.09525900000000001, "total_cost": 0.7783020000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588469} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 31551, "completion_tokens": 98, "total_tokens": 31649, "cost": 0.096123, "total_cost": 0.8744250000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588479} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588511} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588511} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588521} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588521} +{"event": "message_send", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "prompt_tokens": 678, "completion_tokens": 0, "total_tokens": 678, "cost": 0.00010169999999999999, "total_cost": 0.00010169999999999999, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588525} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588566} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 29783, "completion_tokens": 195, "total_tokens": 29978, "cost": 0.092274, "total_cost": 0.9666990000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588582} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 30164, "completion_tokens": 77, "total_tokens": 30241, "cost": 0.091647, "total_cost": 1.058346, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588593} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 30380, "completion_tokens": 75, "total_tokens": 30455, "cost": 0.092265, "total_cost": 1.150611, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588601} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 30594, "completion_tokens": 0, "total_tokens": 30594, "cost": 0.091782, "total_cost": 1.242393, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588606} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588636} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588647} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588647} +{"event": "message_send", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "prompt_tokens": 678, "completion_tokens": 38, "total_tokens": 716, "cost": 0.0001245, "total_cost": 0.0001245, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588652} +{"event": "message_send", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "prompt_tokens": 729, "completion_tokens": 36, "total_tokens": 765, "cost": 0.00013095, "total_cost": 0.00025545, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588659} +{"event": "message_send", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "prompt_tokens": 776, "completion_tokens": 36, "total_tokens": 812, "cost": 0.000138, "total_cost": 0.00039345, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588669} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588678} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588679} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2180, "completion_tokens": 165, "total_tokens": 2345, "cost": 0.009015, "total_cost": 0.009015, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588686} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2357, "completion_tokens": 189, "total_tokens": 2546, "cost": 0.009906, "total_cost": 0.018921, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588695} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588696} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588708} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588718} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588718} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588724} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 15851, "completion_tokens": 465, "total_tokens": 16316, "cost": 0.054528, "total_cost": 0.054528, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588748} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588763} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 23325, "completion_tokens": 406, "total_tokens": 23731, "cost": 0.076065, "total_cost": 0.130593, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588786} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 24699, "completion_tokens": 185, "total_tokens": 24884, "cost": 0.076872, "total_cost": 0.20746499999999998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588879} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 26276, "completion_tokens": 379, "total_tokens": 26655, "cost": 0.08451299999999999, "total_cost": 0.29197799999999996, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732588920} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732589001} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732589002} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732590455} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591034} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591034} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591041} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591045} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 18103, "completion_tokens": 323, "total_tokens": 18426, "cost": 0.059154000000000005, "total_cost": 0.059154000000000005, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591103} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 19254, "completion_tokens": 360, "total_tokens": 19614, "cost": 0.063162, "total_cost": 0.12231600000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591154} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591167} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591171} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591176} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591179} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591186} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591219} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591219} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 18023, "completion_tokens": 377, "total_tokens": 18400, "cost": 0.059724, "total_cost": 0.059724, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591241} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 19227, "completion_tokens": 244, "total_tokens": 19471, "cost": 0.06134100000000001, "total_cost": 0.121065, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732591266} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596150} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596179} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596380} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596572} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596572} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596575} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 12696, "completion_tokens": 448, "total_tokens": 13144, "cost": 0.044808, "total_cost": 0.044808, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596696} +{"event": "command_read-only", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596803} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 18846, "completion_tokens": 1355, "total_tokens": 20201, "cost": 0.076863, "total_cost": 0.121671, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596855} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596895} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596903} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25551, "completion_tokens": 495, "total_tokens": 26046, "cost": 0.084078, "total_cost": 0.20574900000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732596962} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 26261, "completion_tokens": 286, "total_tokens": 26547, "cost": 0.08307300000000001, "total_cost": 0.288822, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597015} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 26903, "completion_tokens": 289, "total_tokens": 27192, "cost": 0.08504400000000001, "total_cost": 0.37386600000000003, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597025} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597042} +{"event": "model warning", "properties": {"main_model": "ollama/REDACTED", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "ollama/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597044} +{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "ollama/REDACTED", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597051} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597127} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597142} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597160} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597171} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597213} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597219} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597219} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597234} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597253} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 19776, "completion_tokens": 536, "total_tokens": 20312, "cost": 0.067368, "total_cost": 0.067368, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597269} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 20874, "completion_tokens": 396, "total_tokens": 21270, "cost": 0.068562, "total_cost": 0.13593, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597383} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 21299, "completion_tokens": 352, "total_tokens": 21651, "cost": 0.06917699999999999, "total_cost": 0.20510699999999998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597412} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597565} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597565} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597569} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597572} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 14000, "completion_tokens": 403, "total_tokens": 14403, "cost": 0.048045000000000004, "total_cost": 0.048045000000000004, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597588} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597657} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732597657} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629182} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629183} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629208} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 1957, "completion_tokens": 190, "total_tokens": 2147, "cost": 0.008721, "total_cost": 0.008721, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629213} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629226} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629229} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 1856, "completion_tokens": 201, "total_tokens": 2057, "cost": 0.008583, "total_cost": 0.017304, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629234} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629247} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629498} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629498} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629506} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629522} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629528} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629534} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629534} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629536} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629537} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629566} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 1520, "completion_tokens": 257, "total_tokens": 1777, "cost": 0.008414999999999999, "total_cost": 0.008414999999999999, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629572} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 3908, "completion_tokens": 178, "total_tokens": 4086, "cost": 0.014394, "total_cost": 0.022809, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629590} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629810} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629810} +{"event": "command_run", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629845} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 13799, "completion_tokens": 212, "total_tokens": 14011, "cost": 0.044577000000000006, "total_cost": 0.044577000000000006, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629908} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629926} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629930} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629933} +{"event": "command_run", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732629936} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630010} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630010} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630022} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630041} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 3438, "completion_tokens": 358, "total_tokens": 3796, "cost": 0.015684, "total_cost": 0.015684, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630177} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 4101, "completion_tokens": 307, "total_tokens": 4408, "cost": 0.016908, "total_cost": 0.032591999999999996, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630202} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 4604, "completion_tokens": 46, "total_tokens": 4650, "cost": 0.014502, "total_cost": 0.047094, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630254} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630259} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 23076, "completion_tokens": 198, "total_tokens": 23274, "cost": 0.072198, "total_cost": 0.072198, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630273} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630389} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630390} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630394} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630539} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 23226, "completion_tokens": 319, "total_tokens": 23545, "cost": 0.074463, "total_cost": 0.074463, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630567} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630788} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 23205, "completion_tokens": 183, "total_tokens": 23388, "cost": 0.07236, "total_cost": 0.07236, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630799} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630865} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630865} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630868} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630869} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 17486, "completion_tokens": 436, "total_tokens": 17922, "cost": 0.058998, "total_cost": 0.058998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630974} +{"event": "command_diff", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732630980} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631019} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 24958, "completion_tokens": 1033, "total_tokens": 25991, "cost": 0.09036899999999999, "total_cost": 0.149367, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631050} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631055} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 23518, "completion_tokens": 1, "total_tokens": 23519, "cost": 0.070569, "total_cost": 0.070569, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631062} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631071} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 23501, "completion_tokens": 197, "total_tokens": 23698, "cost": 0.073458, "total_cost": 0.073458, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631086} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 30391, "completion_tokens": 502, "total_tokens": 30893, "cost": 0.098703, "total_cost": 0.24807, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631113} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 30342, "completion_tokens": 308, "total_tokens": 30650, "cost": 0.095646, "total_cost": 0.343716, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631184} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631548} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631548} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631572} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 22536, "completion_tokens": 496, "total_tokens": 23032, "cost": 0.075048, "total_cost": 0.075048, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631587} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25163, "completion_tokens": 410, "total_tokens": 25573, "cost": 0.081639, "total_cost": 0.15668700000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631606} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631685} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 24886, "completion_tokens": 285, "total_tokens": 25171, "cost": 0.078933, "total_cost": 0.078933, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732631699} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632227} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632228} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632258} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632258} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632261} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 17477, "completion_tokens": 820, "total_tokens": 18297, "cost": 0.064731, "total_cost": 0.064731, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632359} +{"event": "command_diff", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632370} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632387} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25098, "completion_tokens": 717, "total_tokens": 25815, "cost": 0.086049, "total_cost": 0.15078, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632410} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632516} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25909, "completion_tokens": 431, "total_tokens": 26340, "cost": 0.084192, "total_cost": 0.084192, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632538} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632673} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732632674} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633005} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633005} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633011} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633022} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633153} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633153} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2183, "completion_tokens": 93, "total_tokens": 2276, "cost": 0.007944, "total_cost": 0.007944, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633162} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 24729, "completion_tokens": 590, "total_tokens": 25319, "cost": 0.083037, "total_cost": 0.083037, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633163} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25460, "completion_tokens": 309, "total_tokens": 25769, "cost": 0.081015, "total_cost": 0.164052, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633266} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 26399, "completion_tokens": 122, "total_tokens": 26521, "cost": 0.081027, "total_cost": 0.245079, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633314} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633320} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 26783, "completion_tokens": 246, "total_tokens": 27029, "cost": 0.084039, "total_cost": 0.329118, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633352} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633364} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25924, "completion_tokens": 119, "total_tokens": 26043, "cost": 0.079557, "total_cost": 0.408675, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633386} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 26352, "completion_tokens": 0, "total_tokens": 26352, "cost": 0.079056, "total_cost": 0.487731, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633391} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633393} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 24862, "completion_tokens": 111, "total_tokens": 24973, "cost": 0.076251, "total_cost": 0.563982, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633405} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633407} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633424} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633428} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633452} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633453} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 31923, "completion_tokens": 575, "total_tokens": 32498, "cost": 0.10439400000000001, "total_cost": 0.668376, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633454} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 33758, "completion_tokens": 163, "total_tokens": 33921, "cost": 0.103719, "total_cost": 0.772095, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633482} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633494} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633497} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633500} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 31257, "completion_tokens": 559, "total_tokens": 31816, "cost": 0.10215600000000001, "total_cost": 0.874251, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633522} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 32320, "completion_tokens": 0, "total_tokens": 32320, "cost": 0.09696, "total_cost": 0.971211, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633540} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633541} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 30462, "completion_tokens": 356, "total_tokens": 30818, "cost": 0.096726, "total_cost": 1.0679370000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633586} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 31643, "completion_tokens": 391, "total_tokens": 32034, "cost": 0.100794, "total_cost": 1.1687310000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633629} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633738} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 27856, "completion_tokens": 483, "total_tokens": 28339, "cost": 0.090813, "total_cost": 0.090813, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633756} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633811} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633811} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 3756, "completion_tokens": 100, "total_tokens": 3856, "cost": 0.012768, "total_cost": 0.012768, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633831} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633840} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633916} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732633916} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732634837} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732634838} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732634847} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7738, "completion_tokens": 178, "total_tokens": 7916, "cost": 0.025884, "total_cost": 0.025884, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732634876} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732634953} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732634953} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 5392, "completion_tokens": 230, "total_tokens": 5622, "cost": 0.019625999999999998, "total_cost": 0.019625999999999998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732635052} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732635055} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732635057} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732635062} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 5582, "completion_tokens": 540, "total_tokens": 6122, "cost": 0.024846, "total_cost": 0.044472, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732635080} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732635109} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 28745, "completion_tokens": 472, "total_tokens": 29217, "cost": 0.09331500000000001, "total_cost": 0.09331500000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732635133} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732635793} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732635794} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732639853} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.64.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732639854} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732640233} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.0"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732640233} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732640396} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732640405} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732640491} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 3088, "completion_tokens": 139, "total_tokens": 3227, "cost": 0.011349, "total_cost": 0.011349, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732640496} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732640509} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 3178, "completion_tokens": 768, "total_tokens": 3946, "cost": 0.021054000000000003, "total_cost": 0.032403, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732640525} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 5955, "completion_tokens": 0, "total_tokens": 5955, "cost": 0.017865, "total_cost": 0.050268, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732640621} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732646529} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732646548} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732646648} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 3003, "completion_tokens": 851, "total_tokens": 3854, "cost": 0.021774, "total_cost": 0.072042, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732646668} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6090, "completion_tokens": 425, "total_tokens": 6515, "cost": 0.024645, "total_cost": 0.096687, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732646705} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732647498} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652841} +{"event": "model warning", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652843} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652859} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652859} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652878} +{"event": "cli session", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652879} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652897} +{"event": "model warning", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652898} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652933} +{"event": "model warning", "properties": {"main_model": "None", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "None", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652934} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652948} +{"event": "model warning", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652950} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652962} +{"event": "model warning", "properties": {"main_model": "gpt-4-0613", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4-0613", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652964} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652985} +{"event": "message_send", "properties": {"main_model": "gpt-4-0613", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4-0613", "edit_format": "diff", "prompt_tokens": 2206, "completion_tokens": 9, "total_tokens": 2215, "cost": 0.06672, "total_cost": 0.06672, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732652988} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653075} +{"event": "message_send", "properties": {"main_model": "gpt-4-0613", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4-0613", "edit_format": "diff", "prompt_tokens": 2206, "completion_tokens": 9, "total_tokens": 2215, "cost": 0.06672, "total_cost": 0.06672, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653077} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653082} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2175, "completion_tokens": 113, "total_tokens": 2288, "cost": 0.00822, "total_cost": 0.00822, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653087} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653095} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2175, "completion_tokens": 83, "total_tokens": 2258, "cost": 0.00259, "total_cost": 0.00259, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653101} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653110} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653234} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653313} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653314} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653421} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.1"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732653422} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661402} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661408} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661422} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 2034, "completion_tokens": 119, "total_tokens": 2153, "cost": 0.007887, "total_cost": 0.007887, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661433} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 9224, "completion_tokens": 385, "total_tokens": 9609, "cost": 0.033447000000000005, "total_cost": 0.041334, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661461} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661501} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661501} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661506} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 2027, "completion_tokens": 206, "total_tokens": 2233, "cost": 0.009171, "total_cost": 0.009171, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661526} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661575} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661576} +{"event": "command_web", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661577} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661586} +{"event": "message_send", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "ask", "prompt_tokens": 2506, "completion_tokens": 179, "total_tokens": 2685, "cost": 0.0004833, "total_cost": 0.0004833, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661589} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661770} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661771} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661773} +{"event": "message_send", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "ask", "prompt_tokens": 82, "completion_tokens": 310, "total_tokens": 392, "cost": 0.0001983, "total_cost": 0.0001983, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661786} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661850} +{"event": "cli session", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "whole", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661851} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661851} +{"event": "message_send", "properties": {"main_model": "gpt-4o-mini", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4o-mini", "edit_format": "ask", "prompt_tokens": 2512, "completion_tokens": 139, "total_tokens": 2651, "cost": 0.0004602, "total_cost": 0.0004602, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661863} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661866} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661867} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661870} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 4484, "completion_tokens": 221, "total_tokens": 4705, "cost": 0.016767, "total_cost": 0.016767, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661881} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661935} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661938} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661939} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661959} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 4500, "completion_tokens": 162, "total_tokens": 4662, "cost": 0.01593, "total_cost": 0.01593, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732661982} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6899, "completion_tokens": 130, "total_tokens": 7029, "cost": 0.022647, "total_cost": 0.038577, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732662010} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 12865, "completion_tokens": 720, "total_tokens": 13585, "cost": 0.04939500000000001, "total_cost": 0.08797200000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732662031} +{"event": "command_diff", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732662040} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 10375, "completion_tokens": 480, "total_tokens": 10855, "cost": 0.038325, "total_cost": 0.126297, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732662108} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732662123} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732662254} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732662330} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732662330} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668587} +{"event": "cli session", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668587} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2177, "completion_tokens": 0, "total_tokens": 2177, "cost": 0.002177, "total_cost": 0.002177, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668590} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668617} +{"event": "cli session", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668617} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668627} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2225, "completion_tokens": 53, "total_tokens": 2278, "cost": 0.00249, "total_cost": 0.00249, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668632} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668784} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2225, "completion_tokens": 53, "total_tokens": 2278, "cost": 0.00249, "total_cost": 0.00249, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668789} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668799} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2225, "completion_tokens": 53, "total_tokens": 2278, "cost": 0.00249, "total_cost": 0.00249, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668804} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668829} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2225, "completion_tokens": 53, "total_tokens": 2278, "cost": 0.00249, "total_cost": 0.00249, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668834} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668859} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668861} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668930} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2325, "completion_tokens": 0, "total_tokens": 2325, "cost": 0.002325, "total_cost": 0.002325, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732668933} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669007} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2325, "completion_tokens": 0, "total_tokens": 2325, "cost": 0.002325, "total_cost": 0.002325, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669009} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669063} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2325, "completion_tokens": 0, "total_tokens": 2325, "cost": 0.002325, "total_cost": 0.002325, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669065} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669111} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669122} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2235, "completion_tokens": 72, "total_tokens": 2307, "cost": 0.002595, "total_cost": 0.002595, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669127} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669143} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2241, "completion_tokens": 54, "total_tokens": 2295, "cost": 0.0025109999999999998, "total_cost": 0.0025109999999999998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669147} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669153} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2241, "completion_tokens": 47, "total_tokens": 2288, "cost": 0.007428, "total_cost": 0.007428, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669157} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669184} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2241, "completion_tokens": 56, "total_tokens": 2297, "cost": 0.002521, "total_cost": 0.002521, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669189} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669207} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2331, "completion_tokens": 0, "total_tokens": 2331, "cost": 0.0023309999999999997, "total_cost": 0.0023309999999999997, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669209} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669319} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2330, "completion_tokens": 0, "total_tokens": 2330, "cost": 0.00233, "total_cost": 0.00233, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669321} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669367} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2330, "completion_tokens": 0, "total_tokens": 2330, "cost": 0.00233, "total_cost": 0.00233, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669370} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669378} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2330, "completion_tokens": 31, "total_tokens": 2361, "cost": 0.007455000000000001, "total_cost": 0.007455000000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669383} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669403} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2321, "completion_tokens": 0, "total_tokens": 2321, "cost": 0.0023209999999999997, "total_cost": 0.0023209999999999997, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669406} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669527} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2175, "completion_tokens": 83, "total_tokens": 2258, "cost": 0.00259, "total_cost": 0.00259, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732669534} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670104} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670105} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670112} +{"event": "command_git", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670117} +{"event": "command_editor", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670120} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 18049, "completion_tokens": 624, "total_tokens": 18673, "cost": 0.06350700000000001, "total_cost": 0.06350700000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670200} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 18845, "completion_tokens": 524, "total_tokens": 19369, "cost": 0.06439500000000001, "total_cost": 0.12790200000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670238} +{"event": "command_undo", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670268} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670362} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670410} +{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 2221, "completion_tokens": 56, "total_tokens": 2277, "cost": 0.0025009999999999998, "total_cost": 0.0025009999999999998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670414} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670423} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2230, "completion_tokens": 35, "total_tokens": 2265, "cost": 0.007215, "total_cost": 0.007215, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670426} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670482} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2230, "completion_tokens": 35, "total_tokens": 2265, "cost": 0.007215, "total_cost": 0.007215, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670485} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670499} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2230, "completion_tokens": 35, "total_tokens": 2265, "cost": 0.007215, "total_cost": 0.007215, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670503} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670603} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670762} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2330, "completion_tokens": 31, "total_tokens": 2361, "cost": 0.007455000000000001, "total_cost": 0.007455000000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670766} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670811} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 2330, "completion_tokens": 31, "total_tokens": 2361, "cost": 0.007455000000000001, "total_cost": 0.007455000000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670815} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670821} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670951} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732670952} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678168} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678168} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678196} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 11571, "completion_tokens": 245, "total_tokens": 11816, "cost": 0.038388, "total_cost": 0.038388, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678205} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678221} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 11834, "completion_tokens": 673, "total_tokens": 12507, "cost": 0.045597, "total_cost": 0.083985, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678237} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678250} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 12392, "completion_tokens": 936, "total_tokens": 13328, "cost": 0.051216, "total_cost": 0.13520100000000002, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678270} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678329} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678330} +{"event": "command_paste", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678331} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 4210, "completion_tokens": 64, "total_tokens": 4274, "cost": 0.013590000000000001, "total_cost": 0.013590000000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678345} +{"event": "command_exit", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678366} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 15472, "completion_tokens": 1344, "total_tokens": 16816, "cost": 0.066576, "total_cost": 0.201777, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678393} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678639} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678639} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678648} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678648} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 226, "completion_tokens": 260, "total_tokens": 486, "cost": 0.0045780000000000005, "total_cost": 0.0045780000000000005, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678664} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 503, "completion_tokens": 240, "total_tokens": 743, "cost": 0.005109, "total_cost": 0.009687000000000001, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678685} +{"event": "command_clear", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678708} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 225, "completion_tokens": 180, "total_tokens": 405, "cost": 0.0033750000000000004, "total_cost": 0.013062, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732678722} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679037} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679037} +{"event": "command_read-only", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679050} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 30601, "completion_tokens": 416, "total_tokens": 31017, "cost": 0.09804299999999999, "total_cost": 0.09804299999999999, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679100} +{"event": "command_run", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679185} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 35687, "completion_tokens": 351, "total_tokens": 36038, "cost": 0.11232600000000001, "total_cost": 0.210369, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679210} +{"event": "command_run", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679218} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679233} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679253} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 36405, "completion_tokens": 512, "total_tokens": 36917, "cost": 0.11689500000000001, "total_cost": 0.327264, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679270} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 39001, "completion_tokens": 464, "total_tokens": 39465, "cost": 0.123963, "total_cost": 0.451227, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679320} +{"event": "command_run", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679332} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 34105, "completion_tokens": 404, "total_tokens": 34509, "cost": 0.108375, "total_cost": 0.5596019999999999, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679362} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 34222, "completion_tokens": 835, "total_tokens": 35057, "cost": 0.115191, "total_cost": 0.674793, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679392} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679483} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679484} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679494} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679495} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679498} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 4198, "completion_tokens": 474, "total_tokens": 4672, "cost": 0.019704, "total_cost": 0.019704, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679525} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679543} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 19326, "completion_tokens": 118, "total_tokens": 19444, "cost": 0.059748, "total_cost": 0.079452, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679565} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679572} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 29776, "completion_tokens": 133, "total_tokens": 29909, "cost": 0.091323, "total_cost": 0.170775, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679587} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679614} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679615} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679621} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 14077, "completion_tokens": 219, "total_tokens": 14296, "cost": 0.045516, "total_cost": 0.045516, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679628} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 16430, "completion_tokens": 91, "total_tokens": 16521, "cost": 0.050655, "total_cost": 0.096171, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679648} +{"event": "command_drop", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679677} +{"event": "command_add", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679679} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7095, "completion_tokens": 311, "total_tokens": 7406, "cost": 0.02595, "total_cost": 0.196725, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679706} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679795} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732679795} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681092} +{"event": "model warning", "properties": {"main_model": "gemini/REDACTED", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/REDACTED", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681094} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681102} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-latest", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-latest", "edit_format": "diff-fenced", "prompt_tokens": 2256, "completion_tokens": 31, "total_tokens": 2287, "cost": 0.00792855, "total_cost": 0.00792855, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681105} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-latest", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-latest", "edit_format": "diff-fenced", "prompt_tokens": 2331, "completion_tokens": 63, "total_tokens": 2394, "cost": 0.008224649999999998, "total_cost": 0.0161532, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681108} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681148} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-latest", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-latest", "edit_format": "diff-fenced", "prompt_tokens": 2356, "completion_tokens": 5, "total_tokens": 2361, "cost": 0.00825125, "total_cost": 0.00825125, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681152} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681165} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-latest", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-latest", "edit_format": "diff-fenced", "prompt_tokens": 2361, "completion_tokens": 18, "total_tokens": 2379, "cost": 0.0082824, "total_cost": 0.0082824, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681169} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681230} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681244} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681271} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681274} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 31, "total_tokens": 684, "cost": 5.8274999999999993e-05, "total_cost": 5.8274999999999993e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681277} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681279} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-001", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-001", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 15, "total_tokens": 668, "cost": 5.3475e-05, "total_cost": 5.3475e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681281} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681289} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681292} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 30, "total_tokens": 783, "cost": 6.547499999999999e-05, "total_cost": 6.547499999999999e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681295} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681297} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-001", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-001", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 10, "total_tokens": 763, "cost": 5.9474999999999996e-05, "total_cost": 5.9474999999999996e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681300} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681302} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-002", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-002", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 30, "total_tokens": 783, "cost": 6.547499999999999e-05, "total_cost": 6.547499999999999e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681306} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681308} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-8b-exp-0827", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-8b-exp-0827", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 42, "total_tokens": 795, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681311} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681313} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-8b-exp-0924", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-8b-exp-0924", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 42, "total_tokens": 795, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681316} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681317} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-exp-0827", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-exp-0827", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 19, "total_tokens": 772, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681321} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681323} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-latest", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-latest", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 34, "total_tokens": 787, "cost": 6.6675e-05, "total_cost": 6.6675e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681326} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681328} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro", "edit_format": "diff-fenced", "prompt_tokens": 2361, "completion_tokens": 18, "total_tokens": 2379, "cost": 0.0084525, "total_cost": 0.0084525, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681332} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681334} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-001", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-001", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 25, "total_tokens": 778, "cost": 0.002898, "total_cost": 0.002898, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681338} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681340} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-002", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-002", "edit_format": "diff", "prompt_tokens": 2363, "completion_tokens": 10, "total_tokens": 2373, "cost": 0.0083755, "total_cost": 0.0083755, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681345} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681347} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-exp-0801", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-exp-0801", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 37, "total_tokens": 790, "cost": 0.0030239999999999998, "total_cost": 0.0030239999999999998, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681352} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681354} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-exp-0827", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-exp-0827", "edit_format": "diff-fenced", "prompt_tokens": 2361, "completion_tokens": 19, "total_tokens": 2380, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681358} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681360} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-latest", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-latest", "edit_format": "diff-fenced", "prompt_tokens": 2361, "completion_tokens": 18, "total_tokens": 2379, "cost": 0.0082824, "total_cost": 0.0082824, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681364} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681366} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-exp-1114", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-exp-1114", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 10, "total_tokens": 763, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681372} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681374} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-gemma-2-27b-it", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-gemma-2-27b-it", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 0, "total_tokens": 753, "cost": 0.00026355, "total_cost": 0.00026355, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681376} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681378} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-gemma-2-9b-it", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-gemma-2-9b-it", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 0, "total_tokens": 753, "cost": 0.00026355, "total_cost": 0.00026355, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681380} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681383} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-pro", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-pro", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 0, "total_tokens": 753, "cost": 0.00026355, "total_cost": 0.00026355, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681385} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681387} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-pro-vision", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-pro-vision", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 0, "total_tokens": 753, "cost": 0.00026355, "total_cost": 0.00026355, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681389} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681485} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681488} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 32, "total_tokens": 685, "cost": 5.8575e-05, "total_cost": 5.8575e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681491} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681493} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-001", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-001", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 15, "total_tokens": 668, "cost": 5.3475e-05, "total_cost": 5.3475e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681495} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681497} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681528} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681531} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 21, "total_tokens": 774, "cost": 6.2775e-05, "total_cost": 6.2775e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681534} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681536} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-001", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-001", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 10, "total_tokens": 763, "cost": 5.9474999999999996e-05, "total_cost": 5.9474999999999996e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681539} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681541} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-002", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-002", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 34, "total_tokens": 787, "cost": 6.6675e-05, "total_cost": 6.6675e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681545} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681546} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-8b-exp-0827", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-8b-exp-0827", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 42, "total_tokens": 795, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681550} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681552} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-8b-exp-0924", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-8b-exp-0924", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 45, "total_tokens": 798, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681555} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681557} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-exp-0827", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-exp-0827", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 18, "total_tokens": 771, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681561} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681563} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-flash-latest", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-flash-latest", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 20, "total_tokens": 773, "cost": 6.2475e-05, "total_cost": 6.2475e-05, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681566} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681568} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro", "edit_format": "diff-fenced", "prompt_tokens": 2261, "completion_tokens": 37, "total_tokens": 2298, "cost": 0.008302, "total_cost": 0.008302, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681571} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681574} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-001", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-001", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 24, "total_tokens": 677, "cost": 0.0025375, "total_cost": 0.0025375, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681577} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681579} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-002", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-002", "edit_format": "diff", "prompt_tokens": 2263, "completion_tokens": 28, "total_tokens": 2291, "cost": 0.0082145, "total_cost": 0.0082145, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681584} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681586} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-exp-0801", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-exp-0801", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 49, "total_tokens": 702, "cost": 0.0027999999999999995, "total_cost": 0.0027999999999999995, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681590} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681592} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-exp-0827", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-exp-0827", "edit_format": "diff-fenced", "prompt_tokens": 2261, "completion_tokens": 45, "total_tokens": 2306, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681596} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681596} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681597} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-1.5-pro-latest", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-1.5-pro-latest", "edit_format": "diff-fenced", "prompt_tokens": 2261, "completion_tokens": 22, "total_tokens": 2283, "cost": 0.0079366, "total_cost": 0.0079366, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681600} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681602} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-exp-1114", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-exp-1114", "edit_format": "whole", "prompt_tokens": 753, "completion_tokens": 9, "total_tokens": 762, "cost": 0.0, "total_cost": 0.0, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681608} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681610} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-gemma-2-27b-it", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-gemma-2-27b-it", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 0, "total_tokens": 653, "cost": 0.00022855, "total_cost": 0.00022855, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681612} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681614} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-gemma-2-9b-it", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-gemma-2-9b-it", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 0, "total_tokens": 653, "cost": 0.00022855, "total_cost": 0.00022855, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681616} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681618} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-pro", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-pro", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 23, "total_tokens": 676, "cost": 0.0002527, "total_cost": 0.0002527, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681621} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681623} +{"event": "message_send", "properties": {"main_model": "gemini/gemini-pro-vision", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gemini/gemini-pro-vision", "edit_format": "whole", "prompt_tokens": 653, "completion_tokens": 0, "total_tokens": 653, "cost": 0.00022855, "total_cost": 0.00022855, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681625} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681656} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 23213, "completion_tokens": 235, "total_tokens": 23448, "cost": 0.073164, "total_cost": 0.073164, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681667} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681679} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732681679} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682162} +{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682162} +{"event": "command_ask", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682176} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 4762, "completion_tokens": 116, "total_tokens": 4878, "cost": 0.016026, "total_cost": 0.016026, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682188} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 5252, "completion_tokens": 472, "total_tokens": 5724, "cost": 0.022836, "total_cost": 0.038861999999999994, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682202} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7910, "completion_tokens": 594, "total_tokens": 8504, "cost": 0.03264, "total_cost": 0.071502, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682247} +{"event": "command_diff", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682351} +{"event": "command_reset", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682448} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682462} +{"event": "gui session", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682462} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7011, "completion_tokens": 71, "total_tokens": 7082, "cost": 0.022098, "total_cost": 0.09359999999999999, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682475} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 11983, "completion_tokens": 296, "total_tokens": 12279, "cost": 0.040389, "total_cost": 0.133989, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682516} +{"event": "launched", "properties": {"python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682550} +{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 24248, "completion_tokens": 210, "total_tokens": 24458, "cost": 0.075894, "total_cost": 0.075894, "python_version": "3.12.6", "os_platform": "Darwin", "os_release": "23.6.0", "machine": "x86_64", "aider_version": "0.65.2.dev"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1732682562} diff --git a/aider/website/assets/sample.aider.conf.yml b/aider/website/assets/sample.aider.conf.yml index 474490d72..7d4d9fdb3 100644 --- a/aider/website/assets/sample.aider.conf.yml +++ b/aider/website/assets/sample.aider.conf.yml @@ -12,26 +12,29 @@ # options: ## show this help message and exit -#help: +#help: xxx ####### # Main: ## Specify the OpenAI API key -#openai-api-key: +#openai-api-key: xxx ## Specify the Anthropic API key -#anthropic-api-key: +#anthropic-api-key: xxx ## Specify the model to use for the main chat -#model: +#model: xxx ## Use claude-3-opus-20240229 model for the main chat #opus: false -## Use claude-3-5-sonnet-20240620 model for the main chat +## Use claude-3-5-sonnet-20241022 model for the main chat #sonnet: false +## Use claude-3-5-haiku-20241022 model for the main chat +#haiku: false + ## Use gpt-4-0613 model for the main chat #4: false @@ -50,26 +53,32 @@ ## Use deepseek/deepseek-coder model for the main chat #deepseek: false +## Use o1-mini model for the main chat +#o1-mini: false + +## Use o1-preview model for the main chat +#o1-preview: false + ################# # Model Settings: ## List known models which match the (partial) MODEL name -#models: +#list-models: xxx ## Specify the api base url -#openai-api-base: +#openai-api-base: xxx ## Specify the api_type -#openai-api-type: +#openai-api-type: xxx ## Specify the api_version -#openai-api-version: +#openai-api-version: xxx ## Specify the deployment_id -#openai-api-deployment-id: +#openai-api-deployment-id: xxx ## Specify the OpenAI organization ID -#openai-organization-id: +#openai-organization-id: xxx ## Specify a file with aider model settings for unknown models #model-settings-file: .aider.model.settings.yml @@ -77,36 +86,62 @@ ## Specify a file with context window and costs for unknown models #model-metadata-file: .aider.model.metadata.json +## Add a model alias (can be used multiple times) +#alias: xxx +## Specify multiple values like this: +#alias: +# - xxx +# - yyy +# - zzz + ## Verify the SSL cert when connecting to models (default: True) #verify-ssl: true ## Specify what edit format the LLM should use (default depends on model) -#edit-format: +#edit-format: xxx + +## Use architect edit format for the main chat +#architect: false ## Specify the model to use for commit messages and chat history summarization (default depends on --model) -#weak-model: +#weak-model: xxx + +## Specify the model to use for editor tasks (default depends on --model) +#editor-model: xxx + +## Specify the edit format for the editor model (default: depends on editor model) +#editor-edit-format: xxx ## Only work with models that have meta-data available (default: True) #show-model-warnings: true -## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024) -#map-tokens: +## Soft limit on tokens for chat history, after which summarization begins. If unspecified, defaults to the model's max_chat_history_tokens. +#max-chat-history-tokens: xxx -## Control how often the repo map is refreshed (default: auto) -#map-refresh: auto +## Specify the .env file to load (default: .env in git root) +#env-file: .env + +################# +# Cache Settings: ## Enable caching of prompts (default: False) #cache-prompts: false +## Number of times to ping at 5min intervals to keep prompt cache warm (default: 0) +#cache-keepalive-pings: false + +################### +# Repomap Settings: + +## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024) +#map-tokens: xxx + +## Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto) +#map-refresh: auto + ## Multiplier for map tokens when no files are specified (default: 2) #map-multiplier-no-files: true -## Maximum number of tokens to use for chat history. If not specified, uses the model's max_chat_history_tokens. -#max-chat-history-tokens: - -## Specify the .env file to load (default: .env in git root) -#env-file: .env - ################ # History Files: @@ -120,7 +155,7 @@ #restore-chat-history: false ## Log the conversation with the LLM to this file (for example, .aider.llm.history) -#llm-history-file: +#llm-history-file: xxx ################## # Output Settings: @@ -141,14 +176,29 @@ #user-input-color: #00cc00 ## Set the color for tool output (default: None) -#tool-output-color: +#tool-output-color: xxx -## Set the color for tool error messages (default: red) +## Set the color for tool error messages (default: #FF2222) #tool-error-color: #FF2222 +## Set the color for tool warning messages (default: #FFA500) +#tool-warning-color: #FFA500 + ## Set the color for assistant output (default: #0088ff) #assistant-output-color: #0088ff +## Set the color for the completion menu (default: terminal's default text color) +#completion-menu-color: xxx + +## Set the background color for the completion menu (default: terminal's default background color) +#completion-menu-bg-color: xxx + +## Set the color for the current item in the completion menu (default: terminal's default background color) +#completion-menu-current-color: xxx + +## Set the background color for the current item in the completion menu (default: terminal's default text color) +#completion-menu-current-bg-color: xxx + ## Set the markdown code theme (default: default, other options include monokai, solarized-dark, solarized-light) #code-theme: default @@ -192,11 +242,14 @@ #commit: false ## Specify a custom prompt for generating commit messages -#commit-prompt: +#commit-prompt: xxx ## Perform a dry run without modifying files (default: False) #dry-run: false +## Skip the sanity check for the git repository (default: False) +#skip-sanity-check-repo: false + ######################## # Fixing and committing: @@ -204,13 +257,18 @@ #lint: false ## Specify lint commands to run for different languages, eg: "python: flake8 --select=..." (can be used multiple times) +#lint-cmd: xxx +## Specify multiple values like this: #lint-cmd: +# - xxx +# - yyy +# - zzz ## Enable/disable automatic linting after changes (default: True) #auto-lint: true ## Specify command to run tests -#test-cmd: +#test-cmd: xxx ## Enable/disable automatic testing after changes (default: False) #auto-test: false @@ -218,23 +276,45 @@ ## Run tests and fix problems found #test: false +############ +# Analytics: + +## Enable/disable analytics for current session (default: random) +#analytics: xxx + +## Specify a file to log analytics events +#analytics-log: xxx + +## Permanently disable analytics +#analytics-disable: false + ################# # Other Settings: ## specify a file to edit (can be used multiple times) +#file: xxx +## Specify multiple values like this: #file: +# - xxx +# - yyy +# - zzz ## specify a read-only file (can be used multiple times) +#read: xxx +## Specify multiple values like this: #read: +# - xxx +# - yyy +# - zzz ## Use VI editing mode in the terminal (default: False) #vim: false -## Specify the language for voice using ISO 639-1 code (default: auto) -#voice-language: en +## Specify the language to use in the chat (default: None, uses system settings) +#chat-language: xxx ## Show the version number and exit -#version: +#version: xxx ## Check for updates and return status in the exit code #just-check-update: false @@ -242,11 +322,23 @@ ## Check for new aider versions on launch #check-update: true +## Show release notes on first run of new version (default: None, ask user) +#show-release-notes: xxx + +## Install the latest version from the main branch +#install-main-branch: false + +## Upgrade aider to the latest version from PyPI +#upgrade: false + ## Apply the changes from the given file instead of running the chat (debug) -#apply: +#apply: xxx + +## Apply clipboard contents as edits using the main model's editor format +#apply-clipboard-edits: false ## Always say yes to every confirmation -#yes: false +#yes-always: false ## Enable verbose output #verbose: false @@ -261,16 +353,40 @@ #exit: false ## Specify a single message to send the LLM, process reply then exit (disables chat mode) -#message: +#message: xxx ## Specify a file containing the message to send the LLM, process reply, then exit (disables chat mode) -#message-file: +#message-file: xxx + +## Load and execute /commands from a file on launch +#load: xxx ## Specify the encoding for input and output (default: utf-8) #encoding: utf-8 ## Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory) -#config: +#config: xxx -## Run aider in your browser +## Run aider in your browser (default: False) #gui: false + +## Enable/disable suggesting shell commands (default: True) +#suggest-shell-commands: true + +## Enable/disable fancy input with history and completion (default: True) +#fancy-input: true + +## Enable/disable detection and offering to add URLs to chat (default: True) +#detect-urls: true + +## Specify which editor to use for the /editor command +#editor: xxx + +################# +# Voice Settings: + +## Audio format for voice recording (default: wav). webm and mp3 require ffmpeg +#voice-format: wav + +## Specify the language for voice using ISO 639-1 code (default: auto) +#voice-language: en diff --git a/aider/website/assets/sample.env b/aider/website/assets/sample.env index e67d4b8a2..3642110af 100644 --- a/aider/website/assets/sample.env +++ b/aider/website/assets/sample.env @@ -33,9 +33,12 @@ ## Use claude-3-opus-20240229 model for the main chat #AIDER_OPUS= -## Use claude-3-5-sonnet-20240620 model for the main chat +## Use claude-3-5-sonnet-20241022 model for the main chat #AIDER_SONNET= +## Use claude-3-5-haiku-20241022 model for the main chat +#AIDER_HAIKU= + ## Use gpt-4-0613 model for the main chat #AIDER_4= @@ -54,11 +57,17 @@ ## Use deepseek/deepseek-coder model for the main chat #AIDER_DEEPSEEK= +## Use o1-mini model for the main chat +#AIDER_O1_MINI= + +## Use o1-preview model for the main chat +#AIDER_O1_PREVIEW= + ################# # Model Settings: ## List known models which match the (partial) MODEL name -#AIDER_MODELS= +#AIDER_LIST_MODELS= ## Specify the api base url #OPENAI_API_BASE= @@ -81,36 +90,57 @@ ## Specify a file with context window and costs for unknown models #AIDER_MODEL_METADATA_FILE=.aider.model.metadata.json +## Add a model alias (can be used multiple times) +#AIDER_ALIAS= + ## Verify the SSL cert when connecting to models (default: True) #AIDER_VERIFY_SSL=true ## Specify what edit format the LLM should use (default depends on model) #AIDER_EDIT_FORMAT= +## Use architect edit format for the main chat +#AIDER_ARCHITECT= + ## Specify the model to use for commit messages and chat history summarization (default depends on --model) #AIDER_WEAK_MODEL= +## Specify the model to use for editor tasks (default depends on --model) +#AIDER_EDITOR_MODEL= + +## Specify the edit format for the editor model (default: depends on editor model) +#AIDER_EDITOR_EDIT_FORMAT= + ## Only work with models that have meta-data available (default: True) #AIDER_SHOW_MODEL_WARNINGS=true -## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024) -#AIDER_MAP_TOKENS= - -## Control how often the repo map is refreshed (default: auto) -#AIDER_MAP_REFRESH=auto - -## Enable caching of prompts (default: False) -#AIDER_CACHE_PROMPTS=false - -## Multiplier for map tokens when no files are specified (default: 2) -#AIDER_MAP_MULTIPLIER_NO_FILES=true - -## Maximum number of tokens to use for chat history. If not specified, uses the model's max_chat_history_tokens. +## Soft limit on tokens for chat history, after which summarization begins. If unspecified, defaults to the model's max_chat_history_tokens. #AIDER_MAX_CHAT_HISTORY_TOKENS= ## Specify the .env file to load (default: .env in git root) #AIDER_ENV_FILE=.env +################# +# Cache Settings: + +## Enable caching of prompts (default: False) +#AIDER_CACHE_PROMPTS=false + +## Number of times to ping at 5min intervals to keep prompt cache warm (default: 0) +#AIDER_CACHE_KEEPALIVE_PINGS=false + +################### +# Repomap Settings: + +## Suggested number of tokens to use for repo map, use 0 to disable (default: 1024) +#AIDER_MAP_TOKENS= + +## Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto) +#AIDER_MAP_REFRESH=auto + +## Multiplier for map tokens when no files are specified (default: 2) +#AIDER_MAP_MULTIPLIER_NO_FILES=true + ################ # History Files: @@ -147,12 +177,27 @@ ## Set the color for tool output (default: None) #AIDER_TOOL_OUTPUT_COLOR= -## Set the color for tool error messages (default: red) +## Set the color for tool error messages (default: #FF2222) #AIDER_TOOL_ERROR_COLOR=#FF2222 +## Set the color for tool warning messages (default: #FFA500) +#AIDER_TOOL_WARNING_COLOR=#FFA500 + ## Set the color for assistant output (default: #0088ff) #AIDER_ASSISTANT_OUTPUT_COLOR=#0088ff +## Set the color for the completion menu (default: terminal's default text color) +#AIDER_COMPLETION_MENU_COLOR= + +## Set the background color for the completion menu (default: terminal's default background color) +#AIDER_COMPLETION_MENU_BG_COLOR= + +## Set the color for the current item in the completion menu (default: terminal's default background color) +#AIDER_COMPLETION_MENU_CURRENT_COLOR= + +## Set the background color for the current item in the completion menu (default: terminal's default text color) +#AIDER_COMPLETION_MENU_CURRENT_BG_COLOR= + ## Set the markdown code theme (default: default, other options include monokai, solarized-dark, solarized-light) #AIDER_CODE_THEME=default @@ -201,6 +246,9 @@ ## Perform a dry run without modifying files (default: False) #AIDER_DRY_RUN=false +## Skip the sanity check for the git repository (default: False) +#AIDER_SKIP_SANITY_CHECK_REPO=false + ######################## # Fixing and committing: @@ -222,6 +270,18 @@ ## Run tests and fix problems found #AIDER_TEST=false +############ +# Analytics: + +## Enable/disable analytics for current session (default: random) +#AIDER_ANALYTICS= + +## Specify a file to log analytics events +#AIDER_ANALYTICS_LOG= + +## Permanently disable analytics +#AIDER_ANALYTICS_DISABLE=false + ################# # Other Settings: @@ -234,8 +294,8 @@ ## Use VI editing mode in the terminal (default: False) #AIDER_VIM=false -## Specify the language for voice using ISO 639-1 code (default: auto) -#AIDER_VOICE_LANGUAGE=en +## Specify the language to use in the chat (default: None, uses system settings) +#AIDER_CHAT_LANGUAGE= ## Check for updates and return status in the exit code #AIDER_JUST_CHECK_UPDATE=false @@ -243,11 +303,23 @@ ## Check for new aider versions on launch #AIDER_CHECK_UPDATE=true +## Show release notes on first run of new version (default: None, ask user) +#AIDER_SHOW_RELEASE_NOTES= + +## Install the latest version from the main branch +#AIDER_INSTALL_MAIN_BRANCH=false + +## Upgrade aider to the latest version from PyPI +#AIDER_UPGRADE=false + ## Apply the changes from the given file instead of running the chat (debug) #AIDER_APPLY= +## Apply clipboard contents as edits using the main model's editor format +#AIDER_APPLY_CLIPBOARD_EDITS=false + ## Always say yes to every confirmation -#AIDER_YES= +#AIDER_YES_ALWAYS= ## Enable verbose output #AIDER_VERBOSE=false @@ -267,8 +339,32 @@ ## Specify a file containing the message to send the LLM, process reply, then exit (disables chat mode) #AIDER_MESSAGE_FILE= +## Load and execute /commands from a file on launch +#AIDER_LOAD= + ## Specify the encoding for input and output (default: utf-8) #AIDER_ENCODING=utf-8 -## Run aider in your browser +## Run aider in your browser (default: False) #AIDER_GUI=false + +## Enable/disable suggesting shell commands (default: True) +#AIDER_SUGGEST_SHELL_COMMANDS=true + +## Enable/disable fancy input with history and completion (default: True) +#AIDER_FANCY_INPUT=true + +## Enable/disable detection and offering to add URLs to chat (default: True) +#AIDER_DETECT_URLS=true + +## Specify which editor to use for the /editor command +#AIDER_EDITOR= + +################# +# Voice Settings: + +## Audio format for voice recording (default: wav). webm and mp3 require ffmpeg +#AIDER_VOICE_FORMAT=wav + +## Specify the language for voice using ISO 639-1 code (default: auto) +#AIDER_VOICE_LANGUAGE=en diff --git a/aider/website/assets/sonnet-seems-fine.jpg b/aider/website/assets/sonnet-seems-fine.jpg new file mode 100644 index 000000000..8fceeb789 Binary files /dev/null and b/aider/website/assets/sonnet-seems-fine.jpg differ diff --git a/aider/website/docs/benchmarks-1106.md b/aider/website/docs/benchmarks-1106.md index 600642bc9..b563e8a25 100644 --- a/aider/website/docs/benchmarks-1106.md +++ b/aider/website/docs/benchmarks-1106.md @@ -19,7 +19,7 @@ and there's a lot of interest about their ability to code compared to the previous versions. With that in mind, I've been benchmarking the new models. -[Aider](https://github.com/paul-gauthier/aider) +[Aider](https://github.com/Aider-AI/aider) is an open source command line chat tool that lets you work with GPT to edit code in your local git repo. To do this, aider needs to be able to reliably recognize when GPT wants to edit diff --git a/aider/website/docs/benchmarks-speed-1106.md b/aider/website/docs/benchmarks-speed-1106.md index 59c70cd8d..a415704d9 100644 --- a/aider/website/docs/benchmarks-speed-1106.md +++ b/aider/website/docs/benchmarks-speed-1106.md @@ -20,7 +20,7 @@ and there's a lot of interest about their capabilities and performance. With that in mind, I've been benchmarking the new models. -[Aider](https://github.com/paul-gauthier/aider) +[Aider](https://github.com/Aider-AI/aider) is an open source command line chat tool that lets you work with GPT to edit code in your local git repo. Aider relies on a diff --git a/aider/website/docs/benchmarks.md b/aider/website/docs/benchmarks.md index b7d68af96..c37c96eea 100644 --- a/aider/website/docs/benchmarks.md +++ b/aider/website/docs/benchmarks.md @@ -55,7 +55,7 @@ about prompting GPT for complex tasks like coding. It's beneficial to minimize the "cognitive overhead" of formatting the response, allowing GPT to concentrate on the coding task at hand. -As a thought experiment, imagine a slack conversation with a junior developer where +As a thought experiment, imagine a slack conversation with a editor developer where you ask them to write the code to add some new feature to your app. They're going to type the response back to you by hand in the chat. Should they type out the @@ -168,7 +168,7 @@ requests: ### whole The -[whole](https://github.com/paul-gauthier/aider/blob/main/aider/coders/wholefile_prompts.py) +[whole](https://github.com/Aider-AI/aider/blob/main/aider/coders/wholefile_prompts.py) format asks GPT to return an updated copy of the entire file, including any changes. The file should be formatted with normal markdown triple-backtick fences, inlined with the rest of its response text. @@ -187,7 +187,7 @@ def main(): ### diff -The [diff](https://github.com/paul-gauthier/aider/blob/main/aider/coders/editblock_prompts.py) +The [diff](https://github.com/Aider-AI/aider/blob/main/aider/coders/editblock_prompts.py) format also asks GPT to return edits as part of the normal response text, in a simple diff format. Each edit is a fenced code block that @@ -209,7 +209,7 @@ demo.py ### whole-func -The [whole-func](https://github.com/paul-gauthier/aider/blob/main/aider/coders/wholefile_func_coder.py) +The [whole-func](https://github.com/Aider-AI/aider/blob/main/aider/coders/wholefile_func_coder.py) format requests updated copies of whole files to be returned using the function call API. @@ -227,7 +227,7 @@ format requests updated copies of whole files to be returned using the function ### diff-func The -[diff-func](https://github.com/paul-gauthier/aider/blob/main/aider/coders/editblock_func_coder.py) +[diff-func](https://github.com/Aider-AI/aider/blob/main/aider/coders/editblock_func_coder.py) format requests a list of original/updated style edits to be returned using the function call API. diff --git a/aider/website/docs/config/adv-model-settings.md b/aider/website/docs/config/adv-model-settings.md index e3bba0010..46715349d 100644 --- a/aider/website/docs/config/adv-model-settings.md +++ b/aider/website/docs/config/adv-model-settings.md @@ -11,6 +11,13 @@ description: Configuring advanced settings for LLMs. In most cases, you can safely ignore aider's warning about unknown context window size and model costs. +{: .note } +Aider never *enforces* token limits, it only *reports* token limit errors +from the API provider. +You probably don't need to +configure aider with the proper token limits +for unusual models. + But, you can register context window limits and costs for models that aren't known to aider. Create a `.aider.model.metadata.json` file in one of these locations: @@ -55,8 +62,10 @@ These model settings are pre-configured for most popular models. But it can sometimes be helpful to override them or add settings for a model that aider doesn't know about. -To do that, -create a `.aider.model.settings.yml` file in one of these locations: + +### Configuration file locations + +You can override or add settings for any model by creating a `.aider.model.settings.yml` file in one of these locations: - Your home directory. - The root if your git repo. @@ -66,26 +75,1185 @@ create a `.aider.model.settings.yml` file in one of these locations: If the files above exist, they will be loaded in that order. Files loaded last will take priority. -The yaml file should be a a list of dictionary objects for each model, as follows: +The yaml file should be a list of dictionary objects for each model. + +### Global extra params + +You can use the special model name `aider/extra_params` to define +`extra_params` that will be passed to `litellm.completion()` for all models. +Only the `extra_params` dict is used from this special model name. + +For example: + +```yaml +- name: aider/extra_params + extra_params: + extra_headers: + Custom-Header: value + max_tokens: 8192 ``` -- name: "gpt-3.5-turbo" - edit_format: "whole" - weak_model_name: "gpt-3.5-turbo" - use_repo_map: false - send_undo_reply: false - accepts_images: false + +These settings will be merged with any model-specific settings, with the +`aider/extra_params` settings taking precedence for any direct conflicts. + +### Example model settings + +Below are all the pre-configured model settings to give a sense for the settings which are supported. + +You can also look at the `ModelSettings` class in +[models.py](https://github.com/Aider-AI/aider/blob/main/aider/models.py) +file for more details about all of the model setting that aider supports. + + +```yaml +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null lazy: false + name: gpt-3.5-turbo reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null examples_as_sys_msg: false -- name: "gpt-4-turbo-2024-04-09" - edit_format: "udiff" - weak_model_name: "gpt-3.5-turbo" - use_repo_map: true - send_undo_reply: true - accepts_images: true + extra_params: null + lazy: false + name: gpt-3.5-turbo-0125 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gpt-3.5-turbo-1106 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gpt-3.5-turbo-0613 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gpt-3.5-turbo-16k-0613 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: udiff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null lazy: true + name: gpt-4-turbo-2024-04-09 reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: udiff + editor_edit_format: null + editor_model_name: null examples_as_sys_msg: false + extra_params: null + lazy: true + name: gpt-4-turbo + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: openai/gpt-4o + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: openai/gpt-4o-2024-08-06 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: gpt-4o-2024-08-06 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: gpt-4o-2024-11-20 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: openai/gpt-4o-2024-11-20 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: gpt-4o + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: gpt-4o-mini + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: openai/gpt-4o-mini + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: openai/gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: udiff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: null + lazy: true + name: gpt-4-0125-preview + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: udiff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: gpt-4-1106-preview + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gpt-4-vision-preview + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: null + lazy: false + name: gpt-4-0314 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gpt-4-0613 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gpt-4-32k-0613 + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: claude-3-opus-20240229 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: claude-3-5-haiku-20241022 +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: openrouter/anthropic/claude-3-opus + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: openrouter/anthropic/claude-3-5-haiku +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: claude-3-sonnet-20240229 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: claude-3-5-haiku-20241022 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: claude-3-5-sonnet-20240620 + examples_as_sys_msg: true + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + max_tokens: 8192 + lazy: false + name: claude-3-5-sonnet-20240620 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: claude-3-5-haiku-20241022 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: anthropic/claude-3-5-sonnet-20240620 + examples_as_sys_msg: true + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + max_tokens: 8192 + lazy: false + name: anthropic/claude-3-5-sonnet-20240620 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: anthropic/claude-3-5-haiku-20241022 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: anthropic/claude-3-5-sonnet-20241022 + examples_as_sys_msg: true + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + max_tokens: 8192 + lazy: false + name: anthropic/claude-3-5-sonnet-20241022 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: anthropic/claude-3-5-haiku-20241022 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + examples_as_sys_msg: true + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + max_tokens: 8192 + lazy: false + name: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: anthropic/claude-3-5-sonnet-20241022 + examples_as_sys_msg: true + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + max_tokens: 8192 + lazy: false + name: anthropic/claude-3-5-sonnet-latest + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: anthropic/claude-3-5-haiku-20241022 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: claude-3-5-sonnet-20241022 + examples_as_sys_msg: true + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + max_tokens: 8192 + lazy: false + name: claude-3-5-sonnet-20241022 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: claude-3-5-haiku-20241022 +- cache_control: true + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + lazy: false + name: anthropic/claude-3-haiku-20240307 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: anthropic/claude-3-haiku-20240307 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + lazy: false + name: anthropic/claude-3-5-haiku-20241022 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: anthropic/claude-3-5-haiku-20241022 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + lazy: false + name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + lazy: false + name: claude-3-5-haiku-20241022 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: claude-3-5-haiku-20241022 +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: + max_tokens: 4096 + lazy: false + name: vertex_ai/claude-3-5-haiku@20241022 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: vertex_ai/claude-3-5-haiku@20241022 +- cache_control: true + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: + extra_headers: + anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25 + lazy: false + name: claude-3-haiku-20240307 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: claude-3-haiku-20240307 +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: openrouter/anthropic/claude-3.5-sonnet + examples_as_sys_msg: true + extra_params: + max_tokens: 8192 + lazy: false + name: openrouter/anthropic/claude-3.5-sonnet + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: openrouter/anthropic/claude-3-5-haiku +- cache_control: true + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: openrouter/anthropic/claude-3.5-sonnet:beta + examples_as_sys_msg: true + extra_params: + max_tokens: 8192 + lazy: false + name: openrouter/anthropic/claude-3.5-sonnet:beta + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: openrouter/anthropic/claude-3-5-haiku:beta +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: vertex_ai/claude-3-5-sonnet@20240620 + examples_as_sys_msg: true + extra_params: + max_tokens: 8192 + lazy: false + name: vertex_ai/claude-3-5-sonnet@20240620 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: vertex_ai/claude-3-5-haiku@20241022 +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: vertex_ai/claude-3-5-sonnet-v2@20241022 + examples_as_sys_msg: true + extra_params: + max_tokens: 8192 + lazy: false + name: vertex_ai/claude-3-5-sonnet-v2@20241022 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: vertex_ai/claude-3-5-haiku@20241022 +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: vertex_ai/claude-3-opus@20240229 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: vertex_ai/claude-3-5-haiku@20241022 +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: vertex_ai/claude-3-sonnet@20240229 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: vertex_ai/claude-3-5-haiku@20241022 +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: command-r-plus + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: command-r-plus +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: command-r-08-2024 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: command-r-08-2024 +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: command-r-plus-08-2024 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: command-r-plus-08-2024 +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: null + lazy: false + name: groq/llama3-70b-8192 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: groq/llama3-8b-8192 +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: null + lazy: false + name: openrouter/meta-llama/llama-3-70b-instruct + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: openrouter/meta-llama/llama-3-70b-instruct +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gemini/gemini-1.5-pro-002 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gemini/gemini-1.5-flash-002 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: diff-fenced + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gemini/gemini-1.5-pro + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: diff-fenced + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gemini/gemini-1.5-pro-latest + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: diff-fenced + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gemini/gemini-1.5-pro-exp-0827 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: diff-fenced + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: vertex_ai/gemini-pro-experimental + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: false + name: gemini/gemini-1.5-flash-exp-0827 + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: false + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: + max_tokens: 8192 + lazy: false + name: deepseek/deepseek-chat + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: true + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: + max_tokens: 8192 + lazy: false + name: deepseek/deepseek-coder + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: + max_tokens: 8192 + lazy: false + name: deepseek-chat + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: true + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: + max_tokens: 8192 + lazy: false + name: deepseek-coder + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: null + editor_model_name: null + examples_as_sys_msg: true + extra_params: null + lazy: false + name: openrouter/deepseek/deepseek-coder + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: null +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: null + examples_as_sys_msg: false + extra_params: null + lazy: true + name: openrouter/openai/gpt-4o + reminder: sys + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: openrouter/openai/gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: editor-diff + editor_model_name: openai/gpt-4o + examples_as_sys_msg: false + extra_params: null + lazy: false + name: openai/o1-mini + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: false + use_temperature: false + weak_model_name: openai/gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: editor-diff + editor_model_name: azure/gpt-4o + examples_as_sys_msg: false + extra_params: null + lazy: false + name: azure/o1-mini + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: false + use_temperature: false + weak_model_name: azure/gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: editor-diff + editor_model_name: gpt-4o + examples_as_sys_msg: false + extra_params: null + lazy: false + name: o1-mini + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: false + use_temperature: false + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: openai/gpt-4o + examples_as_sys_msg: false + extra_params: null + lazy: false + name: openai/o1-preview + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: false + use_temperature: false + weak_model_name: openai/gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: azure/gpt-4o + examples_as_sys_msg: false + extra_params: null + lazy: false + name: azure/o1-preview + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: false + use_temperature: false + weak_model_name: azure/gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: architect + editor_edit_format: editor-diff + editor_model_name: gpt-4o + examples_as_sys_msg: false + extra_params: null + lazy: false + name: o1-preview + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: false + use_temperature: false + weak_model_name: gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: whole + editor_edit_format: editor-diff + editor_model_name: openrouter/openai/gpt-4o + examples_as_sys_msg: false + extra_params: null + lazy: false + name: openrouter/openai/o1-mini + reminder: user + send_undo_reply: false + streaming: false + use_repo_map: true + use_system_prompt: false + use_temperature: false + weak_model_name: openrouter/openai/gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: openrouter/openai/gpt-4o + examples_as_sys_msg: false + extra_params: null + lazy: false + name: openrouter/openai/o1-preview + reminder: user + send_undo_reply: false + streaming: false + use_repo_map: true + use_system_prompt: false + use_temperature: false + weak_model_name: openrouter/openai/gpt-4o-mini +- cache_control: false + caches_by_default: false + edit_format: diff + editor_edit_format: editor-diff + editor_model_name: openrouter/qwen/qwen-2.5-coder-32b-instruct + examples_as_sys_msg: false + extra_params: null + lazy: false + name: openrouter/qwen/qwen-2.5-coder-32b-instruct + reminder: user + send_undo_reply: false + streaming: true + use_repo_map: true + use_system_prompt: true + use_temperature: true + weak_model_name: openrouter/qwen/qwen-2.5-coder-32b-instruct ``` + + diff --git a/aider/website/docs/config/aider_conf.md b/aider/website/docs/config/aider_conf.md index 348943a2a..2d931e54b 100644 --- a/aider/website/docs/config/aider_conf.md +++ b/aider/website/docs/config/aider_conf.md @@ -21,11 +21,28 @@ load whichever is found first. {% include env-keys-tip.md %} +## A note on lists + +Lists of values can be specified either as a bulleted list: + +``` +read: + - CONVENTIONS.md + - anotherfile.txt + - thirdfile.py +``` + +Or lists can be specified using commas and square brackets: + +``` +read: [CONVENTIONS.md, anotherfile.txt, thirdfile.py] +``` + ## Sample YAML config file Below is a sample of the YAML config file, which you can also -[download from GitHub](https://github.com/paul-gauthier/aider/blob/main/aider/website/assets/sample.aider.conf.yml). +[download from GitHub](https://github.com/Aider-AI/aider/blob/main/aider/website/assets/sample.aider.conf.yml). diff --git a/aider/website/docs/config/dotenv.md b/aider/website/docs/config/dotenv.md index 62e53cceb..3dbec38dd 100644 --- a/aider/website/docs/config/dotenv.md +++ b/aider/website/docs/config/dotenv.md @@ -28,7 +28,7 @@ If the files above exist, they will be loaded in that order. Files loaded last w Below is a sample `.env` file, which you can also -[download from GitHub](https://github.com/paul-gauthier/aider/blob/main/aider/website/assets/sample.env). +[download from GitHub](https://github.com/Aider-AI/aider/blob/main/aider/website/assets/sample.env). diff --git a/aider/website/docs/config/editor.md b/aider/website/docs/config/editor.md new file mode 100644 index 000000000..b09985c4e --- /dev/null +++ b/aider/website/docs/config/editor.md @@ -0,0 +1,127 @@ +--- +parent: Configuration +nav_order: 15 +description: How to configure a custom editor for aider's /editor command +--- + +# Editor configuration + +Aider allows you to configure your preferred text editor for use with the `/editor` command. The editor must be capable of running in "blocking mode", meaning the command line will wait until you close the editor before proceeding. + +## Using `--editor` + +You can specify the text editor with the `--editor` switch or using +`editor:` in aider's +[yaml config file](https://aider.chat/docs/config/aider_conf.html). + +## Environment variables + +Aider checks the following environment variables in order to determine which editor to use: + +1. `AIDER_EDITOR` +2. `VISUAL` +3. `EDITOR` + +## Default behavior + +If no editor is configured, aider will use these platform-specific defaults: + +- Windows: `notepad` +- macOS: `vim` +- Linux/Unix: `vi` + +## Using a custom editor + +You can set your preferred editor in your shell's configuration file (e.g., `.bashrc`, `.zshrc`): + +```bash +export AIDER_EDITOR=vim +``` + +## Popular Editors by Platform + +### macOS + +1. **vim** + ```bash + export AIDER_EDITOR=vim + ``` + +2. **Emacs** + ```bash + export AIDER_EDITOR=emacs + ``` + +3. **VSCode** + ```bash + export AIDER_EDITOR="code --wait" + ``` + +4. **Sublime Text** + ```bash + export AIDER_EDITOR="subl --wait" + ``` + +5. **BBEdit** + ```bash + export AIDER_EDITOR="bbedit --wait" + ``` + +### Linux + +1. **vim** + ```bash + export AIDER_EDITOR=vim + ``` + +2. **Emacs** + ```bash + export AIDER_EDITOR=emacs + ``` + +3. **nano** + ```bash + export AIDER_EDITOR=nano + ``` + +4. **VSCode** + ```bash + export AIDER_EDITOR="code --wait" + ``` + +5. **Sublime Text** + ```bash + export AIDER_EDITOR="subl --wait" + ``` + +### Windows + +1. **Notepad** + ```bat + set AIDER_EDITOR=notepad + ``` + +2. **VSCode** + ```bat + set AIDER_EDITOR="code --wait" + ``` + +3. **Notepad++** + ```bat + set AIDER_EDITOR="notepad++ -multiInst -notabbar -nosession -noPlugin -waitForClose" + ``` + +## Editor command arguments + +Some editors require specific command-line arguments to operate in blocking mode. The `--wait` flag (or equivalent) is commonly used to make the editor block until the file is closed. + +## Troubleshooting + +If you encounter issues with your editor not blocking (returning to the prompt immediately), verify that: + +1. Your editor supports blocking mode +2. You've included the necessary command-line arguments for blocking mode +3. The editor command is properly quoted if it contains spaces or special characters, e.g.: + ```bash + export AIDER_EDITOR="code --wait" + ``` diff --git a/aider/website/docs/config/model-aliases.md b/aider/website/docs/config/model-aliases.md new file mode 100644 index 000000000..a5e7b1260 --- /dev/null +++ b/aider/website/docs/config/model-aliases.md @@ -0,0 +1,72 @@ +--- +parent: Configuration +nav_order: 1000 +description: Assign convenient short names to models. +--- + +# Model Aliases + +Model aliases allow you to create shorthand names for models you frequently use. This is particularly useful for models with long names or when you want to standardize model usage across your team. + +## Command Line Usage + +You can define aliases when launching aider using the `--alias` option: + +```bash +aider --alias "fast:gpt-3.5-turbo" --alias "smart:gpt-4" +``` + +Multiple aliases can be defined by using the `--alias` option multiple times. Each alias definition should be in the format `alias:model-name`. + +## Configuration File + +You can also define aliases in your [`.aider.conf.yml` file](https://aider.chat/docs/config/aider_conf.html): + +```yaml +alias: + - "fast:gpt-3.5-turbo" + - "smart:gpt-4" + - "hacker:claude-3-sonnet-20240229" +``` + +## Using Aliases + +Once defined, you can use the alias instead of the full model name: + +```bash +aider --model fast # Uses gpt-3.5-turbo +aider --model smart # Uses gpt-4 +``` + +## Built-in Aliases + +Aider includes some built-in aliases for convenience: + + +- `3`: gpt-3.5-turbo +- `35-turbo`: gpt-3.5-turbo +- `35turbo`: gpt-3.5-turbo +- `4`: gpt-4-0613 +- `4-turbo`: gpt-4-1106-preview +- `4o`: gpt-4o-2024-08-06 +- `deepseek`: deepseek/deepseek-coder +- `haiku`: claude-3-5-haiku-20241022 +- `opus`: claude-3-opus-20240229 +- `sonnet`: claude-3-5-sonnet-20241022 + + +## Priority + +If the same alias is defined in multiple places, the priority is: + +1. Command line aliases (highest priority) +2. Configuration file aliases +3. Built-in aliases (lowest priority) + +This allows you to override built-in aliases with your own preferences. diff --git a/aider/website/docs/config/options.md b/aider/website/docs/config/options.md index 550bd8fef..abba8ff0f 100644 --- a/aider/website/docs/config/options.md +++ b/aider/website/docs/config/options.md @@ -26,25 +26,31 @@ cog.out(get_md_help()) ]]]--> ``` usage: aider [-h] [--openai-api-key] [--anthropic-api-key] [--model] - [--opus] [--sonnet] [--4] [--4o] [--mini] [--4-turbo] - [--35turbo] [--deepseek] [--models] [--openai-api-base] + [--opus] [--sonnet] [--haiku] [--4] [--4o] [--mini] + [--4-turbo] [--35turbo] [--deepseek] [--o1-mini] + [--o1-preview] [--list-models] [--openai-api-base] [--openai-api-type] [--openai-api-version] [--openai-api-deployment-id] [--openai-organization-id] [--model-settings-file] [--model-metadata-file] - [--verify-ssl | --no-verify-ssl] [--edit-format] - [--weak-model] + [--alias] [--verify-ssl | --no-verify-ssl] + [--edit-format] [--architect] [--weak-model] + [--editor-model] [--editor-edit-format] [--show-model-warnings | --no-show-model-warnings] - [--map-tokens] [--map-refresh] + [--max-chat-history-tokens] [--env-file] [--cache-prompts | --no-cache-prompts] - [--map-multiplier-no-files] [--max-chat-history-tokens] - [--env-file] [--input-history-file] - [--chat-history-file] + [--cache-keepalive-pings] [--map-tokens] + [--map-refresh] [--map-multiplier-no-files] + [--input-history-file] [--chat-history-file] [--restore-chat-history | --no-restore-chat-history] [--llm-history-file] [--dark-mode] [--light-mode] [--pretty | --no-pretty] [--stream | --no-stream] [--user-input-color] [--tool-output-color] - [--tool-error-color] [--assistant-output-color] - [--code-theme] [--show-diffs] [--git | --no-git] + [--tool-error-color] [--tool-warning-color] + [--assistant-output-color] [--completion-menu-color] + [--completion-menu-bg-color] + [--completion-menu-current-color] + [--completion-menu-current-bg-color] [--code-theme] + [--show-diffs] [--git | --no-git] [--gitignore | --no-gitignore] [--aiderignore] [--subtree-only] [--auto-commits | --no-auto-commits] [--dirty-commits | --no-dirty-commits] @@ -53,13 +59,23 @@ usage: aider [-h] [--openai-api-key] [--anthropic-api-key] [--model] [--attribute-commit-message-author | --no-attribute-commit-message-author] [--attribute-commit-message-committer | --no-attribute-commit-message-committer] [--commit] [--commit-prompt] [--dry-run | --no-dry-run] - [--lint] [--lint-cmd] [--auto-lint | --no-auto-lint] - [--test-cmd] [--auto-test | --no-auto-test] [--test] - [--file] [--read] [--vim] [--voice-language] - [--version] [--just-check-update] - [--check-update | --no-check-update] [--apply] [--yes] - [-v] [--show-repo-map] [--show-prompts] [--exit] - [--message] [--message-file] [--encoding] [-c] [--gui] + [--skip-sanity-check-repo] [--lint] [--lint-cmd] + [--auto-lint | --no-auto-lint] [--test-cmd] + [--auto-test | --no-auto-test] [--test] + [--analytics | --no-analytics] [--analytics-log] + [--analytics-disable] [--file] [--read] [--vim] + [--chat-language] [--version] [--just-check-update] + [--check-update | --no-check-update] + [--show-release-notes | --no-show-release-notes] + [--install-main-branch] [--upgrade] [--apply] + [--apply-clipboard-edits] [--yes-always] [-v] + [--show-repo-map] [--show-prompts] [--exit] [--message] + [--message-file] [--load] [--encoding] [-c] + [--gui | --no-gui | --browser | --no-browser] + [--suggest-shell-commands | --no-suggest-shell-commands] + [--fancy-input | --no-fancy-input] + [--detect-urls | --no-detect-urls] [--editor] + [--voice-format] [--voice-language] ``` @@ -90,9 +106,13 @@ Use claude-3-opus-20240229 model for the main chat Environment variable: `AIDER_OPUS` ### `--sonnet` -Use claude-3-5-sonnet-20240620 model for the main chat +Use claude-3-5-sonnet-20241022 model for the main chat Environment variable: `AIDER_SONNET` +### `--haiku` +Use claude-3-5-haiku-20241022 model for the main chat +Environment variable: `AIDER_HAIKU` + ### `--4` Use gpt-4-0613 model for the main chat Environment variable: `AIDER_4` @@ -125,11 +145,22 @@ Aliases: Use deepseek/deepseek-coder model for the main chat Environment variable: `AIDER_DEEPSEEK` +### `--o1-mini` +Use o1-mini model for the main chat +Environment variable: `AIDER_O1_MINI` + +### `--o1-preview` +Use o1-preview model for the main chat +Environment variable: `AIDER_O1_PREVIEW` + ## Model Settings: -### `--models MODEL` +### `--list-models MODEL` List known models which match the (partial) MODEL name -Environment variable: `AIDER_MODELS` +Environment variable: `AIDER_LIST_MODELS` +Aliases: + - `--list-models MODEL` + - `--models MODEL` ### `--openai-api-base OPENAI_API_BASE` Specify the api base url @@ -161,6 +192,10 @@ Specify a file with context window and costs for unknown models Default: .aider.model.metadata.json Environment variable: `AIDER_MODEL_METADATA_FILE` +### `--alias ALIAS:MODEL` +Add a model alias (can be used multiple times) +Environment variable: `AIDER_ALIAS` + ### `--verify-ssl` Verify the SSL cert when connecting to models (default: True) Default: True @@ -176,10 +211,22 @@ Aliases: - `--edit-format EDIT_FORMAT` - `--chat-mode EDIT_FORMAT` +### `--architect` +Use architect edit format for the main chat +Environment variable: `AIDER_ARCHITECT` + ### `--weak-model WEAK_MODEL` Specify the model to use for commit messages and chat history summarization (default depends on --model) Environment variable: `AIDER_WEAK_MODEL` +### `--editor-model EDITOR_MODEL` +Specify the model to use for editor tasks (default depends on --model) +Environment variable: `AIDER_EDITOR_MODEL` + +### `--editor-edit-format EDITOR_EDIT_FORMAT` +Specify the edit format for the editor model (default: depends on editor model) +Environment variable: `AIDER_EDITOR_EDIT_FORMAT` + ### `--show-model-warnings` Only work with models that have meta-data available (default: True) Default: True @@ -188,14 +235,16 @@ Aliases: - `--show-model-warnings` - `--no-show-model-warnings` -### `--map-tokens VALUE` -Suggested number of tokens to use for repo map, use 0 to disable (default: 1024) -Environment variable: `AIDER_MAP_TOKENS` +### `--max-chat-history-tokens VALUE` +Soft limit on tokens for chat history, after which summarization begins. If unspecified, defaults to the model's max_chat_history_tokens. +Environment variable: `AIDER_MAX_CHAT_HISTORY_TOKENS` -### `--map-refresh VALUE` -Control how often the repo map is refreshed (default: auto) -Default: auto -Environment variable: `AIDER_MAP_REFRESH` +### `--env-file ENV_FILE` +Specify the .env file to load (default: .env in git root) +Default: .env +Environment variable: `AIDER_ENV_FILE` + +## Cache Settings: ### `--cache-prompts` Enable caching of prompts (default: False) @@ -205,20 +254,27 @@ Aliases: - `--cache-prompts` - `--no-cache-prompts` +### `--cache-keepalive-pings VALUE` +Number of times to ping at 5min intervals to keep prompt cache warm (default: 0) +Default: 0 +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) +Environment variable: `AIDER_MAP_TOKENS` + +### `--map-refresh VALUE` +Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto) +Default: auto +Environment variable: `AIDER_MAP_REFRESH` + ### `--map-multiplier-no-files VALUE` Multiplier for map tokens when no files are specified (default: 2) Default: 2 Environment variable: `AIDER_MAP_MULTIPLIER_NO_FILES` -### `--max-chat-history-tokens VALUE` -Maximum number of tokens to use for chat history. If not specified, uses the model's max_chat_history_tokens. -Environment variable: `AIDER_MAX_CHAT_HISTORY_TOKENS` - -### `--env-file ENV_FILE` -Specify the .env file to load (default: .env in git root) -Default: .env -Environment variable: `AIDER_ENV_FILE` - ## History Files: ### `--input-history-file INPUT_HISTORY_FILE` @@ -281,15 +337,36 @@ Set the color for tool output (default: None) Environment variable: `AIDER_TOOL_OUTPUT_COLOR` ### `--tool-error-color VALUE` -Set the color for tool error messages (default: red) +Set the color for tool error messages (default: #FF2222) Default: #FF2222 Environment variable: `AIDER_TOOL_ERROR_COLOR` +### `--tool-warning-color VALUE` +Set the color for tool warning messages (default: #FFA500) +Default: #FFA500 +Environment variable: `AIDER_TOOL_WARNING_COLOR` + ### `--assistant-output-color VALUE` Set the color for assistant output (default: #0088ff) Default: #0088ff Environment variable: `AIDER_ASSISTANT_OUTPUT_COLOR` +### `--completion-menu-color COLOR` +Set the color for the completion menu (default: terminal's default text color) +Environment variable: `AIDER_COMPLETION_MENU_COLOR` + +### `--completion-menu-bg-color COLOR` +Set the background color for the completion menu (default: terminal's default background color) +Environment variable: `AIDER_COMPLETION_MENU_BG_COLOR` + +### `--completion-menu-current-color COLOR` +Set the color for the current item in the completion menu (default: terminal's default background color) +Environment variable: `AIDER_COMPLETION_MENU_CURRENT_COLOR` + +### `--completion-menu-current-bg-color COLOR` +Set the background color for the current item in the completion menu (default: terminal's default text color) +Environment variable: `AIDER_COMPLETION_MENU_CURRENT_BG_COLOR` + ### `--code-theme VALUE` Set the markdown code theme (default: default, other options include monokai, solarized-dark, solarized-light) Default: default @@ -393,6 +470,11 @@ Aliases: - `--dry-run` - `--no-dry-run` +### `--skip-sanity-check-repo` +Skip the sanity check for the git repository (default: False) +Default: False +Environment variable: `AIDER_SKIP_SANITY_CHECK_REPO` + ## Fixing and committing: ### `--lint` @@ -431,6 +513,24 @@ Run tests and fix problems found Default: False Environment variable: `AIDER_TEST` +## Analytics: + +### `--analytics` +Enable/disable analytics for current session (default: random) +Environment variable: `AIDER_ANALYTICS` +Aliases: + - `--analytics` + - `--no-analytics` + +### `--analytics-log ANALYTICS_LOG_FILE` +Specify a file to log analytics events +Environment variable: `AIDER_ANALYTICS_LOG` + +### `--analytics-disable` +Permanently disable analytics +Default: False +Environment variable: `AIDER_ANALYTICS_DISABLE` + ## Other Settings: ### `--file FILE` @@ -446,10 +546,9 @@ Use VI editing mode in the terminal (default: False) Default: False Environment variable: `AIDER_VIM` -### `--voice-language VOICE_LANGUAGE` -Specify the language for voice using ISO 639-1 code (default: auto) -Default: en -Environment variable: `AIDER_VOICE_LANGUAGE` +### `--chat-language CHAT_LANGUAGE` +Specify the language to use in the chat (default: None, uses system settings) +Environment variable: `AIDER_CHAT_LANGUAGE` ### `--version` Show the version number and exit @@ -467,13 +566,38 @@ Aliases: - `--check-update` - `--no-check-update` +### `--show-release-notes` +Show release notes on first run of new version (default: None, ask user) +Environment variable: `AIDER_SHOW_RELEASE_NOTES` +Aliases: + - `--show-release-notes` + - `--no-show-release-notes` + +### `--install-main-branch` +Install the latest version from the main branch +Default: False +Environment variable: `AIDER_INSTALL_MAIN_BRANCH` + +### `--upgrade` +Upgrade aider to the latest version from PyPI +Default: False +Environment variable: `AIDER_UPGRADE` +Aliases: + - `--upgrade` + - `--update` + ### `--apply FILE` Apply the changes from the given file instead of running the chat (debug) Environment variable: `AIDER_APPLY` -### `--yes` +### `--apply-clipboard-edits` +Apply clipboard contents as edits using the main model's editor format +Default: False +Environment variable: `AIDER_APPLY_CLIPBOARD_EDITS` + +### `--yes-always` Always say yes to every confirmation -Environment variable: `AIDER_YES` +Environment variable: `AIDER_YES_ALWAYS` ### `--verbose` Enable verbose output @@ -513,6 +637,10 @@ Aliases: - `--message-file MESSAGE_FILE` - `-f MESSAGE_FILE` +### `--load LOAD_FILE` +Load and execute /commands from a file on launch +Environment variable: `AIDER_LOAD` + ### `--encoding VALUE` Specify the encoding for input and output (default: utf-8) Default: utf-8 @@ -525,10 +653,52 @@ Aliases: - `--config CONFIG_FILE` ### `--gui` -Run aider in your browser +Run aider in your browser (default: False) Default: False Environment variable: `AIDER_GUI` Aliases: - `--gui` + - `--no-gui` - `--browser` + - `--no-browser` + +### `--suggest-shell-commands` +Enable/disable suggesting shell commands (default: True) +Default: True +Environment variable: `AIDER_SUGGEST_SHELL_COMMANDS` +Aliases: + - `--suggest-shell-commands` + - `--no-suggest-shell-commands` + +### `--fancy-input` +Enable/disable fancy input with history and completion (default: True) +Default: True +Environment variable: `AIDER_FANCY_INPUT` +Aliases: + - `--fancy-input` + - `--no-fancy-input` + +### `--detect-urls` +Enable/disable detection and offering to add URLs to chat (default: True) +Default: True +Environment variable: `AIDER_DETECT_URLS` +Aliases: + - `--detect-urls` + - `--no-detect-urls` + +### `--editor VALUE` +Specify which editor to use for the /editor command +Environment variable: `AIDER_EDITOR` + +## Voice Settings: + +### `--voice-format VOICE_FORMAT` +Audio format for voice recording (default: wav). webm and mp3 require ffmpeg +Default: wav +Environment variable: `AIDER_VOICE_FORMAT` + +### `--voice-language VOICE_LANGUAGE` +Specify the language for voice using ISO 639-1 code (default: auto) +Default: en +Environment variable: `AIDER_VOICE_LANGUAGE` diff --git a/aider/website/docs/ctags.md b/aider/website/docs/ctags.md index b57f8de33..72096dacf 100644 --- a/aider/website/docs/ctags.md +++ b/aider/website/docs/ctags.md @@ -12,6 +12,7 @@ nav_exclude: true ![robot flowchat](/assets/robot-flowchart.png) + ## Updated Aider no longer uses ctags to build a repo map. @@ -111,9 +112,9 @@ like functions and methods also include their signatures. Here's a sample of the map of the aider repo, just showing the maps of -[main.py](https://github.com/paul-gauthier/aider/blob/main/aider/main.py) +[main.py](https://github.com/Aider-AI/aider/blob/main/aider/main.py) and -[io.py](https://github.com/paul-gauthier/aider/blob/main/aider/io.py) +[io.py](https://github.com/Aider-AI/aider/blob/main/aider/io.py) : ``` @@ -228,7 +229,7 @@ Some possible approaches to reducing the amount of map data are: - Distill the global map, to prioritize important symbols and discard "internal" or otherwise less globally relevant identifiers. Possibly enlist `gpt-3.5-turbo` to perform this distillation in a flexible and language agnostic way. - Provide a mechanism for GPT to start with a distilled subset of the global map, and let it ask to see more detail about subtrees or keywords that it feels are relevant to the current coding task. - - Attempt to analyize the natural language coding task given by the user and predict which subset of the repo map is relevant. Possibly by analysis of prior coding chats within the specific repo. Work on certain files or types of features may require certain somewhat predictable context from elsewhere in the repo. Vector and keyword search against the chat history, repo map or codebase may help here. + - Attempt to analyze the natural language coding task given by the user and predict which subset of the repo map is relevant. Possibly by analysis of prior coding chats within the specific repo. Work on certain files or types of features may require certain somewhat predictable context from elsewhere in the repo. Vector and keyword search against the chat history, repo map or codebase may help here. One key goal is to prefer solutions which are language agnostic or which can be easily deployed against most popular code languages. diff --git a/aider/website/docs/faq.md b/aider/website/docs/faq.md index 06720ca43..4921f4326 100644 --- a/aider/website/docs/faq.md +++ b/aider/website/docs/faq.md @@ -30,14 +30,14 @@ current chat to build a compact Adding a bunch of files that are mostly irrelevant to the task at hand will often distract or confuse the LLM. The LLM will give worse coding results, and sometimese even fail to correctly edit files. -Addings extra files will also increase the token costs on your OpenAI invoice. +Addings extra files will also increase your token costs. Again, it's usually best to just add the files to the chat that will need to be modified. If you still wish to add lots of files to the chat, you can: - Use a wildcard when you launch aider: `aider src/*.py` - Use a wildcard with the in-chat `/add` command: `/add src/*.py` -- Give the `/add` command a directory name and it will recurisvely add every file under that dir: `/add src` +- Give the `/add` command a directory name and it will recursively add every file under that dir: `/add src` ## Can I use aider in a large (mono) repo? @@ -45,7 +45,14 @@ Aider will work in any size repo, but is not optimized for quick performance and response time in very large repos. There are some things you can do to improve performance. -Change into a sub directory of your repo that contains the +Be sure to check the +[general usage tips](/docs/usage/tips.html) +before considering this large-repo specific advice. +To get the best results from aider you want to +be thoughtful about how you add files to the chat, +regardless of your repo size. + +You can change into a sub directory of your repo that contains the code you want to work on and use the `--subtree-only` switch. This will tell aider to ignore the repo outside of the directory you start in. @@ -53,38 +60,119 @@ directory you start in. You can also create a `.aiderignore` file to tell aider to ignore parts of the repo that aren't relevant to your task. This file conforms to `.gitignore` syntax and conventions. +For example, to focus only on specific directories in a monorepo, +you could create a `.aiderignore` file with: + +``` +# Ignore everything +/* + +# Allow specific directories and their contents +!foo/ +!bar/ +!baz/ + +# Allow nested files under these directories +!foo/** +!bar/** +!baz/** +``` You can use `--aiderignore ` to name a specific file to use for ignore patterns. You might have a few of these handy for when you want to work on frontend, backend, etc portions of your repo. +## Can I use aider with multiple git repos at once? + +Currently aider can only work with one repo at a time. + +There are some things you can try if you need to work with +multiple interrelated repos: + +- You can run aider in repo-A where you need to make a change +and use `/read` to add some files read-only from another repo-B. +This can let aider see key functions or docs from the other repo. +- You can run `aider --show-repo-map > map.md` within each +repo to create repo maps. +You could then run aider in repo-A and +use `/read ../path/to/repo-B/map.md` to share +a high level map of the other repo. +- You can use aider to write documentation about a repo. +Inside each repo, you could run `aider docs.md` +and work with aider to write some markdown docs. +Then while using aider to edit repo-A +you can `/read ../path/to/repo-B/docs.md` to +read in those docs from the other repo. +- In repo A, ask aider to write a small script that demonstrates +the functionality you want to use in repo B. +Then when you're using aider in repo B, you can +`/read` in that script. + +## How do I turn on the repository map? + +Depending on the LLM you are using, aider may launch with the repo map disabled by default: + +``` +Repo-map: disabled +``` + +This is because weaker models get easily overwhelmed and confused by the content of the +repo map. They sometimes mistakenly try to edit the code in the repo map. +The repo map is usually disabled for a good reason. + +If you would like to force it on, you can run aider with `--map-tokens 1024`. + +## How do I include the git history in the context? + +When starting a fresh aider session, you can include recent git history in the chat context. This can be useful for providing the LLM with information about recent changes. To do this: + +1. Use the `/run` command with `git diff` to show recent changes: + ``` + /run git diff HEAD~1 + ``` + This will include the diff of the last commit in the chat history. + +2. To include diffs from multiple commits, increase the number after the tilde: + ``` + /run git diff HEAD~3 + ``` + This will show changes from the last three commits. + +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. + +{: .tip } +The `/git` command will not work for this purpose, as its output is not included in the chat. + ## How can I run aider locally from source code? To run the project locally, follow these steps: ``` -# Clone the repository: -git clone git@github.com:paul-gauthier/aider.git +# Clone the repository +git clone git@github.com:Aider-AI/aider.git -# Navigate to the project directory: +# Navigate to the project directory cd aider # It's recommended to make a virtual environment -# Install the dependencies listed in the `requirements.txt` file: +# Install aider in editable/development mode, +# so it runs from the latest copy of these source files python -m pip install -e . -# Run the local version of Aider: +# Run the local version of aider python -m aider ``` - ## Can I change the system prompts that aider uses? -Aider is set up to support different system prompts and edit formats +The most convenient way to add custom instructions is to use a +[conventions file](https://aider.chat/docs/usage/conventions.html). + +But, aider is set up to support different actual system prompts and edit formats in a modular way. If you look in the `aider/coders` subdirectory, you'll see there's a base coder with base prompts, and then there are a number of @@ -122,18 +210,67 @@ You can also refer to the [instructions for installing a development version of aider](https://aider.chat/docs/install/optional.html#install-the-development-version-of-aider). +## How are the "aider wrote xx% of code" stats computed? + +[Aider is tightly integrated with git](/docs/git.html) so all +of aider's code changes are committed to the repo with proper attribution. +The +[stats are computed](https://github.com/Aider-AI/aider/blob/main/scripts/blame.py) +by doing something like `git blame` on the repo, +and counting up who wrote all the new lines of code in each release. +Only lines in source code files are counted, not documentation or prompt files. + +## Why is the LLM speaking to me in an unexpected language? + +Aider goes to some effort to prompt the model to use the language that is configured +for your system. +But LLMs aren't fully reliable, and they sometimes decide to speak in +an unexpected language. +Claude is especially fond of speaking French. + +You can explicitly set the language that aider tells the model to use with +`--chat-language `. +But the LLM may not comply. + ## Can I share my aider chat transcript? Yes, you can now share aider chat logs in a pretty way. 1. Copy the markdown logs you want to share from `.aider.chat.history.md` and make a github gist. Or publish the raw markdown logs on the web any way you'd like. -https://gist.github.com/paul-gauthier/2087ab8b64034a078c0a209440ac8be0 + ``` + https://gist.github.com/Aider-AI/2087ab8b64034a078c0a209440ac8be0 + ``` 2. Take the gist URL and append it to: -https://aider.chat/share/?mdurl= + ``` + https://aider.chat/share/?mdurl= + ``` This will give you a URL like this, which shows the chat history like you'd see in a terminal: -https://aider.chat/share/?mdurl=https://gist.github.com/paul-gauthier/2087ab8b64034a078c0a209440ac8be0 +``` +https://aider.chat/share/?mdurl=https://gist.github.com/Aider-AI/2087ab8b64034a078c0a209440ac8be0 +``` + +## Can I edit files myself while aider is running? + +Yes. Aider always reads the latest copy of files from the file +system when you send each message. + +While you're waiting for aider's reply to complete, it's probably unwise to +edit files that you've added to the chat. +Your edits and aider's edits might conflict. + +## What is Aider AI LLC? + +Aider AI LLC is the company behind the aider AI coding tool. +Aider is +[open source and available on GitHub](https://github.com/Aider-AI/aider) +under an +[Apache 2.0 license](https://github.com/Aider-AI/aider/blob/main/LICENSE.txt). + + +
+ diff --git a/aider/website/docs/git.md b/aider/website/docs/git.md index 32e5e4d36..3c17de47f 100644 --- a/aider/website/docs/git.md +++ b/aider/website/docs/git.md @@ -1,6 +1,6 @@ --- parent: More info -nav_order: 800 +nav_order: 100 description: Aider is tightly integrated with git. --- @@ -22,9 +22,16 @@ This keeps your edits separate from aider's edits, and makes sure you never lose ## In-chat commands -Aider also allows you to use in-chat commands to `/diff` or `/undo` the last change. -To do more complex management of your git history, you cat use raw `git` commands, -either by using `/git` within the chat, or with standard git tools outside of aider. +Aider also allows you to use +[in-chat commands](/docs/usage/commands.html) +to perform git operations: + +- `/diff` will show all the file changes since the last message you sent. +- `/undo` will undo and discard the last change. +- `/commit` to commit all dirty changes with a sensible commit message. +- `/git` will let you run raw git commands to do more complex management of your git history. + +You can also manage your git history outside of aider with your preferred git tools. ## Disabling git integration @@ -36,15 +43,18 @@ While it is not recommended, you can disable aider's use of git in a few ways: ## Commit messages +Aider sends the `--weak-model` a copy of the diffs and the chat history +and asks it to produce a commit message. By default, aider creates commit messages which follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). You can customize the -[commit prompt](https://github.com/paul-gauthier/aider/blob/main/aider/prompts.py#L5) +[commit prompt](https://github.com/Aider-AI/aider/blob/main/aider/prompts.py#L5) with the `--commit-prompt` option. You can place that on the command line, or [configure it via a config file or environment variables](https://aider.chat/docs/config.html). + ## Commit attribution Aider marks commits that it either authored or committed. diff --git a/aider/website/docs/install/install.md b/aider/website/docs/install/install.md index 71cf419bf..f2dad3648 100644 --- a/aider/website/docs/install/install.md +++ b/aider/website/docs/install/install.md @@ -9,6 +9,10 @@ nav_order: 10 - TOC {:toc} +## Python version + +Aider currently works with python 3.9-3.12. + ## Install git Make sure you have git installed. @@ -31,7 +35,7 @@ To work with Anthropic's models like Claude 3.5 Sonnet you need a paid ``` # Install aider -python -m pip install aider-chat +python -m pip install -U --upgrade-strategy only-if-needed aider-chat # To work with GPT-4o: $ aider --4o --openai-api-key sk-xxx... @@ -44,7 +48,7 @@ $ aider --sonnet --anthropic-api-key sk-xxx... ``` # Install aider -python -m pip install aider-chat +python -m pip install -U --upgrade-strategy only-if-needed aider-chat # To work with GPT-4o: $ aider --4o --openai-api-key sk-xxx... diff --git a/aider/website/docs/install/optional.md b/aider/website/docs/install/optional.md index abda81c5a..2bc62d201 100644 --- a/aider/website/docs/install/optional.md +++ b/aider/website/docs/install/optional.md @@ -74,15 +74,11 @@ joshuavial also confirmed that aider works inside a VS Code terminal window. Aider detects if it is running inside VSCode and turns off pretty/color output, since the VSCode terminal doesn't seem to support it well. -[MattFlower](https://github.com/MattFlower) provided a VSCode plugin for aider: - -[https://marketplace.visualstudio.com/items?itemName=MattFlower.aider](https://marketplace.visualstudio.com/items?itemName=MattFlower.aider) - ### Other editors If you are interested in creating an aider plugin for your favorite editor, please let me know by opening a -[GitHub issue](https://github.com/paul-gauthier/aider/issues). +[GitHub issue](https://github.com/Aider-AI/aider/issues). ## Install the development version of aider @@ -91,7 +87,7 @@ If you want the very latest development version of aider you can install directly from GitHub: ``` -python -m pip install --upgrade git+https://github.com/paul-gauthier/aider.git +python -m pip install --upgrade git+https://github.com/Aider-AI/aider.git ``` If you've git cloned the aider repository already, you can install "live" from your local copy. This is mostly useful if you are developing aider and want your current modifications to take effect immediately. diff --git a/aider/website/docs/install/pipx.md b/aider/website/docs/install/pipx.md index a507e3eb9..85cd8abec 100644 --- a/aider/website/docs/install/pipx.md +++ b/aider/website/docs/install/pipx.md @@ -25,3 +25,9 @@ Install [pipx](https://pipx.pypa.io/stable/) then just do: ``` pipx install aider-chat ``` + + +## pipx on replit + +{% include replit-pipx.md %} + diff --git a/aider/website/docs/languages.md b/aider/website/docs/languages.md index 34055c084..417850ff1 100644 --- a/aider/website/docs/languages.md +++ b/aider/website/docs/languages.md @@ -1,6 +1,6 @@ --- parent: More info -nav_order: 900 +nav_order: 200 description: Aider supports pretty much all popular coding languages. --- # Supported languages @@ -21,6 +21,33 @@ Aider can currently produce repository maps for many popular mainstream languages, listed below. +## How to add support for another language + +Aider should work quite well for other languages, even those +without repo map or linter support. +You should really try coding with aider before +assuming it needs better support for your language. + +That said, if aider already has support for linting your language, +then it should be possible to add repo map support. +To build a repo map, aider needs the `tags.scm` file +from the given language's tree-sitter grammar. +If you can find and share that file in a +[GitHub issue](https://github.com/Aider-AI/aider/issues), +then it may be possible to add repo map support. + +If aider doesn't support linting, it will be complicated to +add linting and repo map support. +That is because aider relies on +[py-tree-sitter-languages](https://github.com/grantjenks/py-tree-sitter-languages) +to provide pre-packaged versions of tree-sitter +parsers for many languages. + +Aider needs to be easy for users to install in many environments, +and it is probably too complex to add dependencies on +additional individual tree-sitter parsers. + + - -## How to add support for another language - -Aider should work quite well for other languages, even those -without repo map or linter support. -You should really try coding with aider before -assuming it needs better support for your language. - -That said, if aider already has support for linting your language, -then it should be possible to add repo map support. -To build a repo map, aider needs the `tags.scm` file -from the given language's tree-sitter grammar. -If you can find and share that file in a -[GitHub issue](https://github.com/paul-gauthier/aider/issues), -then it may be possible to add repo map support. - -If aider doesn't support linting, it will be complicated to -add linting and repo map support. -That is because aider relies on -[py-tree-sitter-languages](https://github.com/grantjenks/py-tree-sitter-languages) -to provide pre-packaged versions of tree-sitter -parsers for many languages. - -Aider needs to be easy for users to install in many environments, -and it is probably too complex to add dependencies on -additional individual tree-sitter parsers. diff --git a/aider/website/docs/leaderboards/index.md b/aider/website/docs/leaderboards/index.md index d5eef6af6..6cf043378 100644 --- a/aider/website/docs/leaderboards/index.md +++ b/aider/website/docs/leaderboards/index.md @@ -31,6 +31,8 @@ This measures the LLM's coding ability, and whether it can write new code that integrates into existing code. The model also has to successfully apply all its changes to the source file without human intervention. + + @@ -58,79 +60,7 @@ The model also has to successfully apply all its changes to the source file with