Compare commits

...

169 Commits

Author SHA1 Message Date
Paul Gauthier
f2a893c0d4 set version to 0.77.1.dev 2025-03-13 14:44:50 -07:00
Paul Gauthier
371a03c794 version bump to 0.77.0 2025-03-13 14:44:47 -07:00
Paul Gauthier
88e3d48be5 copy 2025-03-13 14:24:19 -07:00
Paul Gauthier
e8a8681a75 chore: Update polyglot leaderboard YAML files with new test case data 2025-03-13 14:16:20 -07:00
Paul Gauthier
b541eec3b8 chore: Add new model settings to model-settings.yml 2025-03-13 14:08:36 -07:00
Paul Gauthier (aider)
ce3f732645 style: Format Model class constructor for readability 2025-03-13 14:00:27 -07:00
Paul Gauthier (aider)
1b3cae1ed5 feat: Add verbose flag to conditionally dump kwargs in Model.send 2025-03-13 14:00:20 -07:00
Paul Gauthier
024b9130a0 copy 2025-03-12 16:22:26 -07:00
Paul Gauthier
61a8b6020f copy 2025-03-12 16:07:38 -07:00
Paul Gauthier
d25877aace Merge branch 'tsl-pack-add' 2025-03-12 15:58:28 -07:00
Paul Gauthier
c3c2d4dc22 bump deps 2025-03-12 15:57:21 -07:00
Paul Gauthier
7454154599 copy 2025-03-12 15:56:33 -07:00
Paul Gauthier (aider)
04ecea614b refactor: Simplify _test_language_repo_map signature and use self.fixtures_dir 2025-03-12 15:38:07 -07:00
Paul Gauthier (aider)
084a14b640 style: Remove unnecessary blank lines in test_repomap.py 2025-03-12 15:36:18 -07:00
Paul Gauthier (aider)
a477759a49 refactor: Update fixtures_dir references to use self.fixtures_dir 2025-03-12 15:36:13 -07:00
Paul Gauthier
d4df207612 refactor: Move fixtures_dir initialization to setUp in TestRepoMapAllLanguages 2025-03-12 15:36:12 -07:00
Paul Gauthier (aider)
57d492d4b8 style: Remove trailing whitespace in test_repomap.py 2025-03-12 15:34:28 -07:00
Paul Gauthier (aider)
fb7413436c refactor: Split language tests into individual test methods 2025-03-12 15:34:24 -07:00
Paul Gauthier
2cc8105e68 refactor: Split language tests into individual cases in test_repomap.py 2025-03-12 15:34:22 -07:00
Paul Gauthier (aider)
a83d5ff123 style: Format test_repomap.py with linter 2025-03-12 15:32:20 -07:00
Paul Gauthier (aider)
a709d650df refactor: Extract language test loop into helper method 2025-03-12 15:32:16 -07:00
Paul Gauthier
570e8eae31 refactor: Extract loop logic into helper method in test_repomap.py 2025-03-12 15:32:15 -07:00
Paul Gauthier (aider)
22f1703bee test: Update udev fixture to match query patterns 2025-03-12 15:30:23 -07:00
Paul Gauthier (aider)
14037eaeb8 test: add udev test case to TestRepoMapAllLanguages 2025-03-12 15:22:56 -07:00
Paul Gauthier (aider)
189d64dc3d test: Add Swift test case to TestRepoMapAllLanguages 2025-03-12 15:22:16 -07:00
Paul Gauthier (aider)
315f8093c6 test: Add Solidity test case and fixture to TestRepoMapAllLanguages 2025-03-12 15:21:45 -07:00
Paul Gauthier (aider)
a776d70e0d test: add Racket test case and fixture 2025-03-12 15:18:47 -07:00
Paul Gauthier (aider)
1ab6c70ac7 feat: Add R language test case and fixture for repository mapping 2025-03-12 15:16:02 -07:00
Paul Gauthier (aider)
73eb8701dd feat: Add properties language test case and fixture file 2025-03-12 15:13:56 -07:00
Paul Gauthier (aider)
a503f291e7 feat: Add Pony language test case and fixture 2025-03-12 15:12:56 -07:00
Paul Gauthier (aider)
b54d800024 feat: Add Lua language support to TestRepoMapAllLanguages 2025-03-12 15:11:31 -07:00
Paul Gauthier (aider)
d74068464d feat: Add Gleam language support to TestRepoMapAllLanguages 2025-03-12 15:09:43 -07:00
Paul Gauthier (aider)
86a5e8dbe1 feat: Add Elm fixture with Person type and main function 2025-03-12 15:08:36 -07:00
Paul Gauthier (aider)
24d2b683c8 feat: Add Dart language support to TestRepoMapAllLanguages 2025-03-12 15:06:27 -07:00
Paul Gauthier (aider)
9451f0abe4 feat: Add D language test fixture and update test mapping 2025-03-12 15:05:05 -07:00
Paul Gauthier (aider)
544d58ddbd feat: Add CommonLisp language support to TestRepoMapAllLanguages 2025-03-12 15:02:55 -07:00
Paul Gauthier (aider)
7c1d2d75e0 feat: Add chatito language support with test fixture 2025-03-12 14:40:43 -07:00
Paul Gauthier (aider)
0b949f47d9 feat: Add C language test fixture for repository mapping 2025-03-12 14:39:59 -07:00
Paul Gauthier (aider)
393b45dd21 feat: Add Arduino fixture file for language recognition test 2025-03-12 14:38:43 -07:00
Paul Gauthier (aider)
6bb43555dc feat: Add Arduino language support to TestRepoMapAllLanguages 2025-03-12 14:37:55 -07:00
Paul Gauthier (aider)
ba03b07602 refactor: Update udev-tags.scm with more specific @name tags 2025-03-12 14:27:50 -07:00
Paul Gauthier (aider)
0ac4c0b97d refactor: Update swift-tags.scm to use more specific @name.definition tags 2025-03-12 14:27:29 -07:00
Paul Gauthier
41e93a4d94 initial 2025-03-12 14:27:11 -07:00
Paul Gauthier (aider)
a0b5b19d38 refactor: Update solidity-tags.scm with more specific @name tags 2025-03-12 14:27:04 -07:00
Paul Gauthier (aider)
65fad5ae30 refactor: Update Rust tags to use more specific @name.definition and @name.reference tags 2025-03-12 14:26:32 -07:00
Paul Gauthier (aider)
a689f2116c refactor: Update ruby-tags.scm to use more specific tag names 2025-03-12 14:25:57 -07:00
Paul Gauthier (aider)
68b5c90d95 refactor: Update Racket tags to use @name.definition and @name.reference formats 2025-03-12 14:25:30 -07:00
Paul Gauthier (aider)
44eb9af7bc refactor: Update r-tags.scm to use more specific name tags 2025-03-12 14:25:12 -07:00
Paul Gauthier (aider)
9e824e6070 refactor: Update python-tags.scm with more specific name tags 2025-03-12 14:24:53 -07:00
Paul Gauthier (aider)
ba6bb527a7 refactor: Update properties-tags.scm to use more specific name tags 2025-03-12 14:24:32 -07:00
Paul Gauthier (aider)
3525eeae54 refactor: Update Pony tags to use .reference and .definition prefixes 2025-03-12 14:24:14 -07:00
Paul Gauthier (aider)
e535e01e83 refactor: Update Lua tags to use more specific reference and definition tags 2025-03-12 14:23:45 -07:00
Paul Gauthier (aider)
3b1c81e50e refactor: Enhance Java tags with specific definition and reference annotations 2025-03-12 14:23:12 -07:00
Paul Gauthier (aider)
89406e5b7d refactor: Update go-tags.scm to use more specific @name tags 2025-03-12 14:22:49 -07:00
Paul Gauthier (aider)
d5cc855c0f refactor: Update gleam-tags.scm to use more specific @name tags 2025-03-12 14:22:16 -07:00
Paul Gauthier (aider)
2ed61eaf92 refactor: Update Elm tags to use .reference and .definition namespaces 2025-03-12 14:21:35 -07:00
Paul Gauthier (aider)
865f71e2cc refactor: Update elixir-tags.scm to use more specific @name.reference and @name.definition tags 2025-03-12 14:21:05 -07:00
Paul Gauthier (aider)
08a75808df refactor: Update elisp-tags.scm to use more specific name tags 2025-03-12 14:20:39 -07:00
Paul Gauthier (aider)
c9dd37db8e refactor: Update dart-tags.scm to use @name.reference and @name.definition tags 2025-03-12 14:20:23 -07:00
Paul Gauthier (aider)
7e86c8a90c refactor: Update d-tags.scm to use more specific @name.reference and @name.definition tags 2025-03-12 14:19:38 -07:00
Paul Gauthier (aider)
b87a5496e9 refactor: Update cpp-tags.scm to use more specific name tags 2025-03-12 14:19:06 -07:00
Paul Gauthier (aider)
9a88363437 refactor: Update CommonLisp tags to use more specific @name.* tags 2025-03-12 14:18:40 -07:00
Paul Gauthier (aider)
c0b9665cfc refactor: Update chatito-tags.scm with explicit definition and reference tags 2025-03-12 14:18:12 -07:00
Paul Gauthier (aider)
70284ce1c2 refactor: Update c-tags.scm to use more specific @name.definition tags 2025-03-12 14:17:54 -07:00
Paul Gauthier (aider)
48621dadaa refactor: Update Arduino tags to use more specific @name.reference and @name.definition tags 2025-03-12 14:17:35 -07:00
Paul Gauthier
e69bad57e4 initial 2025-03-12 14:14:13 -07:00
Paul Gauthier (aider)
f55099e969 feat: Update script to download Tree-Sitter language tags to specific directory 2025-03-12 14:10:14 -07:00
Paul Gauthier (aider)
76994facec style: Apply linter formatting to tsl_pack_langs.py script 2025-03-12 13:55:52 -07:00
Paul Gauthier (aider)
2d843f6e79 feat: Add skip mechanism for existing tags.scm files in language download script 2025-03-12 13:55:47 -07:00
Paul Gauthier (aider)
e15518dd29 style: Fix linter formatting in tsl_pack_langs.py 2025-03-12 13:55:23 -07:00
Paul Gauthier (aider)
011e0fd109 feat: Print GitHub URL when processing each language 2025-03-12 13:55:17 -07:00
Paul Gauthier (aider)
5f125c1812 style: Format Python script with linter 2025-03-12 13:54:36 -07:00
Paul Gauthier (aider)
a6ebed8d16 feat: Improve language tag download script with multi-branch support 2025-03-12 13:54:31 -07:00
Paul Gauthier
849e02cbfb chore: Make tsl_pack_langs.py script executable 2025-03-12 13:54:27 -07:00
Paul Gauthier (aider)
1ab5238405 refactor: Simplify tags URL construction and remove unused import 2025-03-12 13:52:55 -07:00
Paul Gauthier (aider)
ae6192111d style: Format Python script with linter 2025-03-12 13:52:44 -07:00
Paul Gauthier (aider)
59af4114dd feat: Add script to fetch tags.scm files from GitHub repositories 2025-03-12 13:52:39 -07:00
Paul Gauthier
4491b88763 feat: Add script for packing translation languages 2025-03-12 13:52:35 -07:00
Paul Gauthier
92377fc390 fix: Add missing MagicMock import in test_coder.py 2025-03-12 13:45:10 -07:00
Paul Gauthier (aider)
79b8e50412 fix: Mock InputOutput object correctly in test_architect_coder_auto_accept_true 2025-03-12 13:42:27 -07:00
Paul Gauthier (aider)
b5cd39cc50 fix: Add mock for confirm_ask method in test_architect_coder_auto_accept_true 2025-03-12 13:41:39 -07:00
Paul Gauthier (aider)
63c2a98f3c fix: Add missing summarizer mock to ArchitectCoder tests 2025-03-12 13:41:10 -07:00
Paul Gauthier (aider)
c168f78a13 fix: Initialize cur_messages and done_messages in ArchitectCoder test cases 2025-03-12 13:40:15 -07:00
Paul Gauthier (aider)
42d45b4037 fix: Remove unused import of ANY from unittest.mock 2025-03-12 13:39:42 -07:00
Paul Gauthier (aider)
c41df63629 style: Reorder imports and fix whitespace in test_coder.py 2025-03-12 13:38:48 -07:00
Paul Gauthier (aider)
330bb81206 test: Add tests for auto_accept_architect feature in ArchitectCoder 2025-03-12 13:38:41 -07:00
Paul Gauthier (aider)
d84c755ee8 style: Apply linter formatting to redact-cast.py script 2025-03-12 13:28:06 -07:00
Paul Gauthier (aider)
a24ff28031 refactor: Remove 'env' key from .cast file header 2025-03-12 13:28:01 -07:00
Paul Gauthier (aider)
3a837c472e style: Apply linter formatting to redact-cast.py script 2025-03-12 13:25:08 -07:00
Paul Gauthier (aider)
f4880e2ef3 feat: Add ANSI escape sequence stripping for Atuin version detection 2025-03-12 13:25:03 -07:00
Paul Gauthier
a2e4022e31 copy 2025-03-12 13:12:18 -07:00
Paul Gauthier (aider)
5668b41daa feat: Add auto-accept option for architect coder edits 2025-03-12 13:09:41 -07:00
Paul Gauthier (aider)
c052270048 feat: Add --auto-accept-architect option with default true 2025-03-12 13:08:59 -07:00
Paul Gauthier (aider)
70547171ca style: Fix linter formatting in io.py 2025-03-12 12:50:04 -07:00
Paul Gauthier (aider)
881868bf17 refactor: Require 3 characters for autocomplete, except for commands 2025-03-12 12:49:57 -07:00
Paul Gauthier (aider)
e90eb39a9b style: Add whitespace around arithmetic operator in redact-cast.py 2025-03-11 19:30:57 -07:00
Paul Gauthier
9513d307a1 refactor: Reorganize redact script and improve code formatting 2025-03-11 19:30:46 -07:00
Paul Gauthier
533e5ec03f Merge remote-tracking branch 'source-repo/main' into redact 2025-03-11 19:29:57 -07:00
Paul Gauthier (aider)
55f63395c7 fix: Remove unused mock variables and split long comment lines in test_commands.py 2025-03-11 19:25:46 -07:00
Paul Gauthier (aider)
4253d98a73 style: Remove trailing whitespaces in test_commands.py 2025-03-11 19:25:24 -07:00
Paul Gauthier (aider)
0c4af58866 test: Add tests for /reset preserving original read-only files 2025-03-11 19:25:17 -07:00
Paul Gauthier
a5919bd27d copy 2025-03-11 19:12:35 -07:00
Paul Gauthier
5e40974fdd fix: Ensure default model is set only if not already specified 2025-03-11 19:07:53 -07:00
Paul Gauthier (aider)
a27f4d0e04 feat: Add speed-up factor to recording timestamps in redact.py 2025-03-11 17:54:12 -07:00
Paul Gauthier (aider)
1bb3041298 feat: Compress long timestamp gaps to 0.5 seconds in asciinema cast processing 2025-03-11 17:44:20 -07:00
Paul Gauthier
dc6040adda copy 2025-03-11 17:39:08 -07:00
Paul Gauthier
864725ff3d feat: Add command aliases and preserve read-only files in /drop 2025-03-11 17:38:13 -07:00
Paul Gauthier (aider)
0fcbea03e5 style: Format code and remove trailing whitespaces 2025-03-11 17:35:28 -07:00
Paul Gauthier (aider)
2ce63e6ad3 test: Add tests for preserving original read-only files during drop command 2025-03-11 17:35:21 -07:00
Paul Gauthier (aider)
d45af94cee refactor: Simplify original read-only files check in _drop_all_files method 2025-03-11 17:33:57 -07:00
Paul Gauthier (aider)
1f874b654d style: Format code with linter and improve readability 2025-03-11 17:31:22 -07:00
Paul Gauthier (aider)
a7a21757bc feat: Preserve original read-only files when using bare /drop command 2025-03-11 17:31:14 -07:00
Paul Gauthier (aider)
1bed4e8972 feat: Add 0.5 second pause after skipped sections in redaction script 2025-03-11 17:05:54 -07:00
Paul Gauthier (aider)
efcda12dda refactor: Maintain consistent timestamps during section skipping 2025-03-11 17:04:47 -07:00
Paul Gauthier (aider)
d7b4079ab5 refactor: Update redact.py to handle asciinema cast v2 JSON format 2025-03-11 17:03:19 -07:00
Paul Gauthier
2eb1513612 initial 2025-03-11 17:01:26 -07:00
Paul Gauthier
87bcbe0420 copy 2025-03-11 13:00:33 -07:00
Paul Gauthier (aider)
26b0c6e6da style: Add mobile-friendly CSS to hide command and edit columns 2025-03-11 12:51:38 -07:00
Paul Gauthier
8cfbc9b827 Revert "refactor: Improve chart responsiveness with dynamic mobile height"
This reverts commit 46eee9e642.
2025-03-11 12:37:56 -07:00
Paul Gauthier (aider)
46eee9e642 refactor: Improve chart responsiveness with dynamic mobile height 2025-03-11 12:33:45 -07:00
Paul Gauthier
7d902d2f3e test: Update token budget parsing test cases 2025-03-11 12:24:42 -07:00
Paul Gauthier
3d05007024 fix: Correct token budget message formatting in test case 2025-03-11 12:20:47 -07:00
Paul Gauthier (aider)
a2bf2e2910 style: Format long line in test_commands.py for better readability 2025-03-11 12:18:18 -07:00
Paul Gauthier (aider)
9cf4286cee fix: Update test to handle lowercase token budget input 2025-03-11 12:18:10 -07:00
Paul Gauthier (aider)
c9ddca3a16 feat: Update tests for /think and /reason to handle no-argument case 2025-03-11 12:16:54 -07:00
Paul Gauthier
06370cb096 copy 2025-03-11 12:14:47 -07:00
Paul Gauthier (aider)
342586519d fix: Update method calls to use main_model for get_thinking_tokens and get_reasoning_effort 2025-03-11 12:13:52 -07:00
Paul Gauthier (aider)
89174bb524 style: Format code with linter and improve whitespace 2025-03-11 12:12:20 -07:00
Paul Gauthier (aider)
1fa3bc4018 feat: Add display of current values for /think and /reason commands when called without arguments 2025-03-11 12:12:12 -07:00
Paul Gauthier (aider)
d68e2b33fb style: Remove trailing whitespaces in commands.py 2025-03-11 12:11:15 -07:00
Paul Gauthier (aider)
1313cd8216 refactor: Update thinking tokens and reasoning effort display with helper methods 2025-03-11 12:11:08 -07:00
Paul Gauthier (aider)
7afc8c760c feat: Add /think and /reason command aliases for think-tokens and reasoning-effort 2025-03-11 12:10:19 -07:00
Paul Gauthier (aider)
79f714ab16 refactor: Extract thinking tokens and reasoning effort methods into separate functions 2025-03-11 12:09:41 -07:00
Paul Gauthier
e21bab2d17 copy 2025-03-11 11:52:02 -07:00
Paul Gauthier (aider)
4288cf2a39 style: Apply linter formatting to test_commands.py 2025-03-11 11:49:46 -07:00
Paul Gauthier (aider)
9d570a9cb1 feat: Update test values to use 1024 base for k and M suffixes 2025-03-11 11:49:39 -07:00
Paul Gauthier (aider)
333ddfb37a style: Format Python code with linter 2025-03-11 11:48:21 -07:00
Paul Gauthier (aider)
10a5250527 test: Add tests for /think-tokens and /reasoning-effort commands 2025-03-11 11:48:13 -07:00
Paul Gauthier (aider)
fd57eccdca style: Remove trailing whitespaces in commands.py 2025-03-11 11:45:30 -07:00
Paul Gauthier (aider)
1432be9be6 feat: Add announcements output for /think and /reason commands 2025-03-11 11:45:23 -07:00
Paul Gauthier (aider)
1773bbf759 style: Shorten docstring to fix line length flake8 error 2025-03-11 11:43:59 -07:00
Paul Gauthier (aider)
5c94624186 style: Format code with linter 2025-03-11 11:43:47 -07:00
Paul Gauthier (aider)
dc06c2fab3 refactor: Update reasoning effort command to accept string values 2025-03-11 11:43:40 -07:00
Paul Gauthier (aider)
f37799b39c style: Fix linter formatting in base_coder.py 2025-03-11 11:42:46 -07:00
Paul Gauthier (aider)
cc84f590fe feat: Add reasoning effort display in get_announcements output 2025-03-11 11:42:38 -07:00
Paul Gauthier
afcf3e77b5 refactor: Reorder model info output for better readability 2025-03-11 11:42:36 -07:00
Paul Gauthier (aider)
0406dda2a6 feat: Add /reasoning-effort command to set model reasoning effort level 2025-03-11 11:41:46 -07:00
Paul Gauthier (aider)
935227f7e7 refactor: Use 1024 instead of 1000 for token budget formatting 2025-03-11 11:38:11 -07:00
Paul Gauthier (aider)
67ebb2566d style: Use lowercase 'k' for token budget display 2025-03-11 11:37:30 -07:00
Paul Gauthier (aider)
1c736161c5 feat: Omit decimal point for whole number token budget values 2025-03-11 11:37:01 -07:00
Paul Gauthier (aider)
a348c2d013 feat: Change --thinking-tokens argument type to string 2025-03-11 11:36:17 -07:00
Paul Gauthier (aider)
444a95bc6c style: Add whitespace around arithmetic operators in budget formatting 2025-03-11 11:35:49 -07:00
Paul Gauthier (aider)
c38cdef220 style: Format code with linter and improve readability 2025-03-11 11:35:31 -07:00
Paul Gauthier (aider)
5608db0892 feat: Add thinking token budget display in model details 2025-03-11 11:35:23 -07:00
Paul Gauthier
98b3722a02 refactor: Simplify thinking token budget display logic 2025-03-11 11:33:45 -07:00
Paul Gauthier (aider)
2d623ff196 style: Apply linter formatting to commands.py 2025-03-11 11:32:39 -07:00
Paul Gauthier (aider)
703e124277 feat: Add /think-tokens command to set thinking token budget 2025-03-11 11:32:32 -07:00
Paul Gauthier (aider)
68c27f885f style: Fix linting issues in test_models.py 2025-03-11 11:30:28 -07:00
Paul Gauthier (aider)
58cd190ca9 test: Add comprehensive tests for token parsing and thinking tokens methods 2025-03-11 11:30:23 -07:00
Paul Gauthier (aider)
2c5c2b2f67 style: Format code with linter and fix whitespace 2025-03-11 11:29:44 -07:00
Paul Gauthier (aider)
e10fe50c6f feat: Add flexible token parsing for set_thinking_tokens method 2025-03-11 11:29:38 -07:00
Paul Gauthier
b8ad0b15e8 copy 2025-03-11 09:38:28 -07:00
Paul Gauthier (aider)
1b81fb0fdf refactor: Modify git push to stream output directly to terminal 2025-03-11 09:25:44 -07:00
Paul Gauthier
703cb8849d set version to 0.76.3.dev 2025-03-11 09:25:11 -07:00
Paul Gauthier
55f856b23c version bump to 0.76.2 2025-03-11 09:25:07 -07:00
Paul Gauthier (aider)
93c284a67d fix: Handle JSONDecodeError when loading model cache file 2025-03-11 08:33:18 -07:00
Paul Gauthier (aider)
38fd715247 style: Fix linter warnings in main.py 2025-03-11 08:27:23 -07:00
Paul Gauthier (aider)
987d024847 fix: Handle GitCommandError when retrieving git user config 2025-03-11 08:27:17 -07:00
Paul Gauthier
a3c0d628a1 fix: Remove unnecessary default flag in git config retrieval 2025-03-11 08:27:15 -07:00
79 changed files with 3471 additions and 1127 deletions

View File

@@ -1,5 +1,28 @@
# Release history
### main branch
- Big upgrade in [programming languages supported](https://aider.chat/docs/languages.html) by adopting [tree-sitter-language-pack](https://github.com/Goldziher/tree-sitter-language-pack/).
- 130 new languages with linter support.
- 20 new languages with repo-map support.
- Added `/think-tokens` command to set thinking token budget with support for human-readable formats (8k, 10.5k, 0.5M).
- Added `/reasoning-effort` command to control model reasoning level.
- The `/think-tokens` and `/reasoning-effort` commands display current settings when called without arguments.
- Display of thinking token budget and reasoning effort in model information.
- Changed `--thinking-tokens` argument to accept string values with human-readable formats.
- Added `--auto-accept-architect` flag (default: true) to automatically accept changes from architect coder format without confirmation.
- Added support for `cohere_chat/command-a-03-2025` and `gemini/gemma-3-27b-it`
- The bare `/drop` command now preserves original read-only files provided via args.read.
- Fixed a bug where default model would be set by deprecated `--shortcut` switches even when already specified in the command line.
- Improved AutoCompleter to require 3 characters for autocompletion to reduce noise.
- Aider wrote 72% of the code in this release.
### Aider v0.76.2
- Fixed handling of JSONDecodeError when loading model cache file.
- Fixed handling of GitCommandError when retrieving git user configuration.
- Aider wrote 75% of the code in this release.
### Aider v0.76.1
- Added ignore_permission_denied option to file watcher to prevent errors when accessing restricted files, by Yutaka Matsubara.

View File

@@ -1,6 +1,6 @@
from packaging import version
__version__ = "0.76.2.dev"
__version__ = "0.77.1.dev"
safe_version = __version__
try:

View File

@@ -119,7 +119,7 @@ def get_parser(default_config_files, git_root):
)
group.add_argument(
"--thinking-tokens",
type=int,
type=str,
help="Set the thinking token budget for models that support it (default: not set)",
)
group.add_argument(
@@ -148,6 +148,12 @@ def get_parser(default_config_files, git_root):
const="architect",
help="Use architect edit format for the main chat",
)
group.add_argument(
"--auto-accept-architect",
action=argparse.BooleanOptionalAction,
default=True,
help="Enable/disable automatic acceptance of architect changes (default: True)",
)
group.add_argument(
"--weak-model",
metavar="WEAK_MODEL",

View File

@@ -6,6 +6,7 @@ from .base_coder import Coder
class ArchitectCoder(AskCoder):
edit_format = "architect"
gpt_prompts = ArchitectPrompts()
auto_accept_architect = False
def reply_completed(self):
content = self.partial_response_content
@@ -13,7 +14,7 @@ class ArchitectCoder(AskCoder):
if not content or not content.strip():
return
if not self.io.confirm_ask("Edit the files?"):
if not self.auto_accept_architect and not self.io.confirm_ask("Edit the files?"):
return
kwargs = dict()

View File

@@ -207,10 +207,22 @@ class Coder:
prefix = "Model"
output = f"{prefix}: {main_model.name} with {self.edit_format} edit format"
# Check for thinking token budget
thinking_tokens = main_model.get_thinking_tokens(main_model)
if thinking_tokens:
output += f", {thinking_tokens} think tokens"
# Check for reasoning effort
reasoning_effort = main_model.get_reasoning_effort(main_model)
if reasoning_effort:
output += f", reasoning {reasoning_effort}"
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":
@@ -310,6 +322,7 @@ class Coder:
ignore_mentions=None,
file_watcher=None,
auto_copy_context=False,
auto_accept_architect=True,
):
# Fill in a dummy Analytics if needed, but it is never .enable()'d
self.analytics = analytics if analytics is not None else Analytics()
@@ -322,6 +335,7 @@ class Coder:
self.abs_root_path_cache = {}
self.auto_copy_context = auto_copy_context
self.auto_accept_architect = auto_accept_architect
self.ignore_mentions = ignore_mentions
if not self.ignore_mentions:

View File

@@ -59,6 +59,7 @@ class Commands:
parser=None,
verbose=False,
editor=None,
original_read_only_fnames=None,
):
self.io = io
self.coder = coder
@@ -77,6 +78,9 @@ class Commands:
self.help = None
self.editor = editor
# Store the original read-only filenames provided via args.read
self.original_read_only_fnames = set(original_read_only_fnames or [])
def cmd_model(self, args):
"Switch to a new LLM"
@@ -355,7 +359,21 @@ class Commands:
def _drop_all_files(self):
self.coder.abs_fnames = set()
self.coder.abs_read_only_fnames = set()
# When dropping all files, keep those that were originally provided via args.read
if self.original_read_only_fnames:
# Keep only the original read-only files
to_keep = set()
for abs_fname in self.coder.abs_read_only_fnames:
rel_fname = self.coder.get_rel_fname(abs_fname)
if (
abs_fname in self.original_read_only_fnames
or rel_fname in self.original_read_only_fnames
):
to_keep.add(abs_fname)
self.coder.abs_read_only_fnames = to_keep
else:
self.coder.abs_read_only_fnames = set()
def _clear_chat_history(self):
self.coder.done_messages = []
@@ -822,7 +840,12 @@ class Commands:
"Remove files from the chat session to free up context space"
if not args.strip():
self.io.tool_output("Dropping all files from the chat session.")
if self.original_read_only_fnames:
self.io.tool_output(
"Dropping all files from the chat session except originally read-only files."
)
else:
self.io.tool_output("Dropping all files from the chat session.")
self._drop_all_files()
return
@@ -1411,6 +1434,58 @@ class Commands:
if user_input.strip():
self.io.set_placeholder(user_input.rstrip())
def cmd_think_tokens(self, args):
"Set the thinking token budget (supports formats like 8096, 8k, 10.5k, 0.5M)"
model = self.coder.main_model
if not args.strip():
# Display current value if no args are provided
formatted_budget = model.get_thinking_tokens(model)
if formatted_budget is None:
self.io.tool_output("Thinking tokens are not currently set.")
else:
budget = model.extra_params["thinking"].get("budget_tokens")
self.io.tool_output(
f"Current thinking token budget: {budget:,} tokens ({formatted_budget})."
)
return
value = args.strip()
model.set_thinking_tokens(value)
formatted_budget = model.get_thinking_tokens(model)
budget = model.extra_params["thinking"].get("budget_tokens")
self.io.tool_output(f"Set thinking token budget to {budget:,} tokens ({formatted_budget}).")
self.io.tool_output()
# Output announcements
announcements = "\n".join(self.coder.get_announcements())
self.io.tool_output(announcements)
def cmd_reasoning_effort(self, args):
"Set the reasoning effort level (values: number or low/medium/high depending on model)"
model = self.coder.main_model
if not args.strip():
# Display current value if no args are provided
reasoning_value = model.get_reasoning_effort(model)
if reasoning_value is None:
self.io.tool_output("Reasoning effort is not currently set.")
else:
self.io.tool_output(f"Current reasoning effort: {reasoning_value}")
return
value = args.strip()
model.set_reasoning_effort(value)
reasoning_value = model.get_reasoning_effort(model)
self.io.tool_output(f"Set reasoning effort to {reasoning_value}")
self.io.tool_output()
# Output announcements
announcements = "\n".join(self.coder.get_announcements())
self.io.tool_output(announcements)
def cmd_copy_context(self, args=None):
"""Copy the current chat context as markdown, suitable to paste into a web UI"""

View File

@@ -121,5 +121,6 @@ def handle_deprecated_model_args(args, io):
)
# Set the model
args.model = model_name
if not args.model:
args.model = model_name
break

View File

@@ -194,6 +194,11 @@ class AutoCompleter(Completer):
candidates = [word if type(word) is tuple else (word, word) for word in candidates]
last_word = words[-1]
# Only provide completions if the user has typed at least 3 characters
if len(last_word) < 3:
return
completions = []
for word_match, word_insert in candidates:
if word_match.lower().startswith(last_word.lower()):

View File

@@ -126,8 +126,15 @@ def setup_git(git_root, io):
if not repo:
return
user_name = repo.git.config("--default", "", "--get", "user.name") or None
user_email = repo.git.config("--default", "", "--get", "user.email") or None
try:
user_name = repo.git.config("--get", "user.name") or None
except git.exc.GitCommandError:
user_name = None
try:
user_email = repo.git.config("--get", "user.email") or None
except git.exc.GitCommandError:
user_email = None
if user_name and user_email:
return repo.working_tree_dir
@@ -771,6 +778,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
weak_model=args.weak_model,
editor_model=args.editor_model,
editor_edit_format=args.editor_edit_format,
verbose=args.verbose,
)
# Check if deprecated remove_reasoning is set
@@ -859,6 +867,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
parser=parser,
verbose=args.verbose,
editor=args.editor,
original_read_only_fnames=read_only_fnames,
)
summarizer = ChatSummary(
@@ -913,6 +922,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
chat_language=args.chat_language,
detect_urls=args.detect_urls,
auto_copy_context=args.copy_paste,
auto_accept_architect=args.auto_accept_architect,
)
except UnknownEditFormat as err:
io.tool_error(str(err))

View File

@@ -153,7 +153,11 @@ class ModelInfoManager:
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())
try:
self.content = json.loads(self.cache_file.read_text())
except json.JSONDecodeError:
# If the cache file is corrupted, treat it as missing
self.content = None
except OSError:
pass
@@ -226,11 +230,14 @@ model_info_manager = ModelInfoManager()
class Model(ModelSettings):
def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None):
def __init__(
self, model, weak_model=None, editor_model=None, editor_edit_format=None, verbose=False
):
# Map any alias to its canonical name
model = MODEL_ALIASES.get(model, model)
self.name = model
self.verbose = verbose
self.max_chat_history_tokens = 1024
self.weak_model = None
@@ -598,13 +605,81 @@ class Model(ModelSettings):
self.extra_params["extra_body"] = {}
self.extra_params["extra_body"]["reasoning_effort"] = effort
def set_thinking_tokens(self, num):
"""Set the thinking token budget for models that support it"""
if num is not None:
def parse_token_value(self, value):
"""
Parse a token value string into an integer.
Accepts formats: 8096, "8k", "10.5k", "0.5M", "10K", etc.
Args:
value: String or int token value
Returns:
Integer token value
"""
if isinstance(value, int):
return value
if not isinstance(value, str):
return int(value) # Try to convert to int
value = value.strip().upper()
if value.endswith("K"):
multiplier = 1024
value = value[:-1]
elif value.endswith("M"):
multiplier = 1024 * 1024
value = value[:-1]
else:
multiplier = 1
# Convert to float first to handle decimal values like "10.5k"
return int(float(value) * multiplier)
def set_thinking_tokens(self, value):
"""
Set the thinking token budget for models that support it.
Accepts formats: 8096, "8k", "10.5k", "0.5M", "10K", etc.
"""
if value is not None:
num_tokens = self.parse_token_value(value)
self.use_temperature = False
if not self.extra_params:
self.extra_params = {}
self.extra_params["thinking"] = {"type": "enabled", "budget_tokens": num}
self.extra_params["thinking"] = {"type": "enabled", "budget_tokens": num_tokens}
def get_thinking_tokens(self, model):
"""Get formatted thinking token budget if available"""
if (
model.extra_params
and "thinking" in model.extra_params
and "budget_tokens" in model.extra_params["thinking"]
):
budget = model.extra_params["thinking"]["budget_tokens"]
# Format as xx.yK for thousands, xx.yM for millions
if budget >= 1024 * 1024:
value = budget / (1024 * 1024)
if value == int(value):
return f"{int(value)}M"
else:
return f"{value:.1f}M"
else:
value = budget / 1024
if value == int(value):
return f"{int(value)}k"
else:
return f"{value:.1f}k"
return None
def get_reasoning_effort(self, model):
"""Get reasoning effort value if available"""
if (
model.extra_params
and "extra_body" in model.extra_params
and "reasoning_effort" in model.extra_params["extra_body"]
):
return model.extra_params["extra_body"]["reasoning_effort"]
return None
def is_deepseek_r1(self):
name = self.name.lower()
@@ -653,6 +728,8 @@ class Model(ModelSettings):
hash_object = hashlib.sha1(key)
if "timeout" not in kwargs:
kwargs["timeout"] = request_timeout
if self.verbose:
dump(kwargs)
res = litellm.completion(**kwargs)
return hash_object, res

View File

@@ -0,0 +1,7 @@
These scm files are all adapted from the github repositories listed here:
https://github.com/Goldziher/tree-sitter-language-pack/blob/main/sources/language_definitions.json
See this URL for information on the licenses of each repo:
https://github.com/Goldziher/tree-sitter-language-pack/

View File

@@ -0,0 +1,5 @@
(function_declarator
declarator: (identifier) @name.definition.function) @definition.function
(call_expression
function: (identifier) @name.reference.call) @reference.call

View File

@@ -0,0 +1,9 @@
(struct_specifier name: (type_identifier) @name.definition.class body:(_)) @definition.class
(declaration type: (union_specifier name: (type_identifier) @name.definition.class)) @definition.class
(function_declarator declarator: (identifier) @name.definition.function) @definition.function
(type_definition declarator: (type_identifier) @name.definition.type) @definition.type
(enum_specifier name: (type_identifier) @name.definition.type) @definition.type

View File

@@ -0,0 +1,16 @@
; Definitions
(intent_def
(intent) @name.definition.intent) @definition.intent
(slot_def
(slot) @name.definition.slot) @definition.slot
(alias_def
(alias) @name.definition.alias) @definition.alias
; References
(slot_ref
(slot) @name.reference.slot) @reference.slot
(alias_ref
(alias) @name.reference.alias) @reference.alias

View File

@@ -0,0 +1,122 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Function Definitions ;;;;;;;;;;;;;;;;;;;;;;;
(defun_header
function_name: (sym_lit) @name.definition.function) @definition.function
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Function Calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Basically, we consider every list literal with symbol as the
;;; first element to be a call to a function named by that element.
;;; But we must exclude some cases. Note, tree-sitter @ignore
;;; cases only work if they are declared before the cases
;;; we want to include.
;; Exclude lambda lists for function definitions
;; For example:
;;
;; (defun my-func (arg1 arg2) ...)
;;
;; do not treat (arg1 arg2) as a call of function arg1
;;
(defun_header
lambda_list: (list_lit . [(sym_lit) (package_lit)] @ignore))
;; Similar to the above, but for
;;
;; (defmethod m ((type1 param1) (type2 param2)) ...)
;;
;; where list literals having symbol as their first element
;; are nested inside the lambda list.
(defun_header
lambda_list: (list_lit (list_lit . [(sym_lit) (package_lit)] @ignore)))
;;
;; (let ((var ...) (var2 ...)) ...)
;;
;; - exclude var, var2
;; - the same for let*, flet, labels, macrolet, symbol-macrolet
(list_lit . [(sym_lit) (package_lit)] @name.reference.call
. (list_lit (list_lit . [(sym_lit) (package_lit)] @ignore))
(#match? @name.reference.call
"(?i)^(cl:)?(let|let\\*|flet|labels|macrolet|symbol-macrolet)$")
)
;; TODO:
;; - exclude also:
;; - (defclass name (parent parent2)
;; ((slot1 ...)
;; (slot2 ...))
;; exclude the parent, slot1, slot2
;; - (flet ((func-1 (param1 param2))) ...)
;; - we already exclude func-1, but param1 is still recognized
;; as a function call - exclude it too
;; - the same for labels
;; - the same macrolet
;; - what else?
;; (that's a non-goal to completely support all macros
;; and special operators, but every one we support
;; makes the solution a little bit better)
;; - (flet ((func-1 (param1 param2))) ...)
;; - instead of simply excluding it, as we do today,
;; tag func-1 as @local.definition.function (I suppose)
;; - the same for labels, macrolet
;; - @local.scope for let, let*, flet, labels, macrolet
;; - I guess the whole span of the scope text,
;; till the closing paren, should be tagged as @local.scope;
;; Hopefully, combined with @local.definition.function
;; within the scope, the usual @reference.call within
;; that scope will refer to the local definition,
;; and there will be no need to use @local.reference.call
;; (which is more difficult to implement).
;; - When implementing, remember the scope rules differences
;; of let vs let*, flet vs labels.
;; Include all other cases - list literal with symbol as the
;; first element
(list_lit . [(sym_lit) (package_lit)] @name.reference.call) @reference.call
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; classes
(list_lit . [(sym_lit) (package_lit)] @ignore
. [(sym_lit) (package_lit)] @name.definition.class
(#match? @ignore "(?i)^(cl:)?defclass$")
) @definition.class
(list_lit . [(sym_lit) (package_lit)] @ignore
. (quoting_lit [(sym_lit) (package_lit)] @name.reference.class)
(#match? @ignore "(?i)^(cl:)?make-instance$")
) @reference.class
;;; TODO:
;; - @reference.class for base classes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; TODO:
;; - Symbols referenced in defpackage
;;
;; (defpackage ...
;; (:export (symbol-a :symbol-b #:symbol-c "SYMBOL-D")))
;;
;; The goal is to allow quick navigation from the API
;; overview in the form of defpackage, to the definition
;; where user can read parameters, docstring, etc.
;; - The @name must not include the colon, or sharpsign colon, quotes,
;; just symbol-a, symbol-b, symbol-c, sybmol-d
;; - Downcase the names specified as string literals?
;; ("SYMBOL-D" -> symbol-d)
;; - We don't know if the exported symbol is a function, variable,
;; class or something else. The official doc
;; (https://tree-sitter.github.io/tree-sitter/code-navigation-systems)
;; does not even suggest a tag for variable reference.
;; (Although in practice, the `tree-sitter tags` command
;; allows any @reference.* and @definition.* tags)
;; Probably it's better to just use @reference.call for all
;; the symbols in the :export clause.
;;
;; - The same for the export function call:
;;
;; (export '(symbol-a :symbol-b #:symbol-c "SYMBOL-D"))

View File

@@ -0,0 +1,15 @@
(struct_specifier name: (type_identifier) @name.definition.class body:(_)) @definition.class
(declaration type: (union_specifier name: (type_identifier) @name.definition.class)) @definition.class
(function_declarator declarator: (identifier) @name.definition.function) @definition.function
(function_declarator declarator: (field_identifier) @name.definition.function) @definition.function
(function_declarator declarator: (qualified_identifier scope: (namespace_identifier) @local.scope name: (identifier) @name.definition.method)) @definition.method
(type_definition declarator: (type_identifier) @name.definition.type) @definition.type
(enum_specifier name: (type_identifier) @name.definition.type) @definition.type
(class_specifier name: (type_identifier) @name.definition.class) @definition.class

View File

@@ -0,0 +1,26 @@
(module_def (module_declaration (module_fqn) @name.definition.module)) @definition.module
(struct_declaration (struct) . (identifier) @name.definition.class) @definition.class
(interface_declaration (interface) . (identifier) @name.definition.interface) @definition.interface
(enum_declaration (enum) . (identifier) @name.definition.type) @definition.type
(class_declaration (class) . (identifier) @name.definition.class) @definition.class
(constructor (this) @name.definition.method) @definition.method
(destructor (this) @name.definition.method) @definition.method
(postblit (this) @name.definition.method) @definition.method
(manifest_declarator . (identifier) @name.definition.type) @definition.type
(function_declaration (identifier) @name.definition.function) @definition.function
(union_declaration (union) . (identifier) @name.definition.type) @definition.type
(anonymous_enum_declaration (enum_member . (identifier) @name.definition.constant)) @definition.constant
(enum_declaration (enum_member . (identifier) @name.definition.constant)) @definition.constant
(call_expression (identifier) @name.reference.call) @reference.call
(call_expression (type (template_instance (identifier) @name.reference.call))) @reference.call
(parameter (type (identifier) @name.reference.class) @reference.class (identifier))
(variable_declaration (type (identifier) @name.reference.class) @reference.class (declarator))

View File

@@ -0,0 +1,92 @@
(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
(new_expression
(type_identifier) @name.reference.class) @reference.class
(enum_declaration
name: (identifier) @name.definition.enum) @definition.enum
(function_signature
name: (identifier) @name.definition.function) @definition.function
(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.send))) @reference.call
(assignment_expression
left: (assignable_expression
(identifier)
(conditional_assignable_selector
"?."
(identifier) @name.reference.send))) @reference.call
((identifier) @name.reference.send
(selector
"!"?
(conditional_assignable_selector
"?." (identifier) @name.reference.send)?
(unconditional_assignable_selector
"."? (identifier) @name.reference.send)?
(argument_part
(arguments
(argument)*))?)*
(cascade_section
(cascade_selector
(identifier)) @name.reference.send
(argument_part
(arguments
(argument)*))?)?) @reference.call

View File

@@ -0,0 +1,5 @@
;; defun/defsubst
(function_definition name: (symbol) @name.definition.function) @definition.function
;; Treat macros as function definitions for the sake of TAGS.
(macro_definition name: (symbol) @name.definition.function) @definition.function

View File

@@ -0,0 +1,54 @@
; Definitions
; * modules and protocols
(call
target: (identifier) @ignore
(arguments (alias) @name.definition.module)
(#any-of? @ignore "defmodule" "defprotocol")) @definition.module
; * functions/macros
(call
target: (identifier) @ignore
(arguments
[
; zero-arity functions with no parentheses
(identifier) @name.definition.function
; regular function clause
(call target: (identifier) @name.definition.function)
; function clause with a guard clause
(binary_operator
left: (call target: (identifier) @name.definition.function)
operator: "when")
])
(#any-of? @ignore "def" "defp" "defdelegate" "defguard" "defguardp" "defmacro" "defmacrop" "defn" "defnp")) @definition.function
; References
; ignore calls to kernel/special-forms keywords
(call
target: (identifier) @ignore
(#any-of? @ignore "def" "defp" "defdelegate" "defguard" "defguardp" "defmacro" "defmacrop" "defn" "defnp" "defmodule" "defprotocol" "defimpl" "defstruct" "defexception" "defoverridable" "alias" "case" "cond" "else" "for" "if" "import" "quote" "raise" "receive" "require" "reraise" "super" "throw" "try" "unless" "unquote" "unquote_splicing" "use" "with"))
; ignore module attributes
(unary_operator
operator: "@"
operand: (call
target: (identifier) @ignore))
; * function call
(call
target: [
; local
(identifier) @name.reference.call
; remote
(dot
right: (identifier) @name.reference.call)
]) @reference.call
; * pipe into function call
(binary_operator
operator: "|>"
right: (identifier) @name.reference.call) @reference.call
; * modules
(alias) @name.reference.module @reference.module

View File

@@ -0,0 +1,19 @@
(value_declaration (function_declaration_left (lower_case_identifier) @name.definition.function)) @definition.function
(function_call_expr (value_expr (value_qid) @name.reference.function)) @reference.function
(exposed_value (lower_case_identifier) @name.reference.function) @reference.function
(type_annotation ((lower_case_identifier) @name.reference.function) (colon)) @reference.function
(type_declaration ((upper_case_identifier) @name.definition.type) ) @definition.type
(type_ref (upper_case_qid (upper_case_identifier) @name.reference.type)) @reference.type
(exposed_type (upper_case_identifier) @name.reference.type) @reference.type
(type_declaration (union_variant (upper_case_identifier) @name.definition.union)) @definition.union
(value_expr (upper_case_qid (upper_case_identifier) @name.reference.union)) @reference.union
(module_declaration
(upper_case_qid (upper_case_identifier)) @name.definition.module
) @definition.module

View File

@@ -0,0 +1,41 @@
; Modules
(module) @name.reference.module @reference.module
(import alias: (identifier) @name.reference.module) @reference.module
(remote_type_identifier
module: (identifier) @name.reference.module) @reference.module
((field_access
record: (identifier) @name.reference.module)
(#is-not? local)) @reference.module
; Functions
(function
name: (identifier) @name.definition.function) @definition.function
(external_function
name: (identifier) @name.definition.function) @definition.function
(unqualified_import (identifier) @name.reference.function) @reference.function
((function_call
function: (identifier) @name.reference.function) @reference.function
(#is-not? local))
((field_access
record: (identifier) @ignore
field: (label) @name.reference.function)
(#is-not? local)) @reference.function
((binary_expression
operator: "|>"
right: (identifier) @name.reference.function)
(#is-not? local)) @reference.function
; Types
(type_definition
(type_name
name: (type_identifier) @name.definition.type)) @definition.type
(type_definition
(data_constructors
(data_constructor
name: (constructor_name) @name.definition.constructor))) @definition.constructor
(external_type
(type_name
name: (type_identifier) @name.definition.type)) @definition.type
(type_identifier) @name.reference.type @reference.type
(constructor_name) @name.reference.constructor @reference.constructor

View File

@@ -0,0 +1,42 @@
(
(comment)* @doc
.
(function_declaration
name: (identifier) @name.definition.function) @definition.function
(#strip! @doc "^//\\s*")
(#set-adjacent! @doc @definition.function)
)
(
(comment)* @doc
.
(method_declaration
name: (field_identifier) @name.definition.method) @definition.method
(#strip! @doc "^//\\s*")
(#set-adjacent! @doc @definition.method)
)
(call_expression
function: [
(identifier) @name.reference.call
(parenthesized_expression (identifier) @name.reference.call)
(selector_expression field: (field_identifier) @name.reference.call)
(parenthesized_expression (selector_expression field: (field_identifier) @name.reference.call))
]) @reference.call
(type_spec
name: (type_identifier) @name.definition.type) @definition.type
(type_identifier) @name.reference.type @reference.type
(package_clause "package" (package_identifier) @name.definition.module)
(type_declaration (type_spec name: (type_identifier) @name.definition.interface type: (interface_type)))
(type_declaration (type_spec name: (type_identifier) @name.definition.class type: (struct_type)))
(import_declaration (import_spec) @name.reference.module)
(var_declaration (var_spec name: (identifier) @name.definition.variable))
(const_declaration (const_spec name: (identifier) @name.definition.constant))

View File

@@ -0,0 +1,20 @@
(class_declaration
name: (identifier) @name.definition.class) @definition.class
(method_declaration
name: (identifier) @name.definition.method) @definition.method
(method_invocation
name: (identifier) @name.reference.method
arguments: (argument_list) @reference.call)
(interface_declaration
name: (identifier) @name.definition.interface) @definition.interface
(type_list
(type_identifier) @name.reference.interface) @reference.implementation
(object_creation_expression
type: (type_identifier) @name.reference.class) @reference.class
(superclass (type_identifier) @name.reference.class) @reference.class

View File

@@ -0,0 +1,34 @@
(function_declaration
name: [
(identifier) @name.definition.function
(dot_index_expression
field: (identifier) @name.definition.function)
]) @definition.function
(function_declaration
name: (method_index_expression
method: (identifier) @name.definition.method)) @definition.method
(assignment_statement
(variable_list .
name: [
(identifier) @name.definition.function
(dot_index_expression
field: (identifier) @name.definition.function)
])
(expression_list .
value: (function_definition))) @definition.function
(table_constructor
(field
name: (identifier) @name.definition.function
value: (function_definition))) @definition.function
(function_call
name: [
(identifier) @name.reference.call
(dot_index_expression
field: (identifier) @name.reference.call)
(method_index_expression
method: (identifier) @name.reference.method)
]) @reference.call

View File

@@ -0,0 +1,39 @@
;Class definitions @definition.class
;Function definitions @definition.function
;Interface definitions @definition.interface
;Method definitions @definition.method
;Module definitions @definition.module
;Function/method calls @reference.call
;Class reference @reference.class
;Interface implementation @reference.implementation
(
(identifier) @reference.class
(#match? @reference.class "^_*[A-Z][a-zA-Z0-9_]*$")
)
(class_definition (identifier) @name.definition.class) @definition.class
(actor_definition (identifier) @name.definition.class) @definition.class
(primitive_definition (identifier) @name.definition.class) @definition.class
(struct_definition (identifier) @name.definition.class) @definition.class
(type_alias (identifier) @name.definition.class) @definition.class
(trait_definition (identifier) @name.definition.interface) @definition.interface
(interface_definition (identifier) @name.definition.interface) @definition.interface
(constructor (identifier) @name.definition.method) @definition.method
(method (identifier) @name.definition.method) @definition.method
(behavior (identifier) @name.definition.method) @definition.method
(class_definition (type) @name.reference.implementation) @reference.implementation
(actor_definition (type) @name.reference.implementation) @reference.implementation
(primitive_definition (type) @name.reference.implementation) @reference.implementation
(struct_definition (type) @name.reference.implementation) @reference.implementation
(type_alias (type) @name.reference.implementation) @reference.implementation
; calls - not catching all possible call cases of callees for capturing the method name
(call_expression callee: [(identifier) (ffi_identifier)] @name.reference.call) @reference.call
(call_expression callee: (generic_expression [(identifier) (ffi_identifier)] @name.reference.call)) @reference.call
(call_expression callee: (member_expression (identifier) @name.reference.call .)) @reference.call
(call_expression callee: (member_expression (generic_expression [(identifier) (ffi_identifier)] @name.reference.call) .)) @reference.call
; TODO: add more possible callee expressions
(call_expression) @reference.call

View File

@@ -0,0 +1,5 @@
(property
(key) @name.definition.property) @definition.property
(substitution
(key) @name.reference.property) @reference.property

View File

@@ -0,0 +1,14 @@
(module (expression_statement (assignment left: (identifier) @name.definition.constant) @definition.constant))
(class_definition
name: (identifier) @name.definition.class) @definition.class
(function_definition
name: (identifier) @name.definition.function) @definition.function
(call
function: [
(identifier) @name.reference.call
(attribute
attribute: (identifier) @name.reference.call)
]) @reference.call

View File

@@ -0,0 +1,21 @@
(binary_operator
lhs: (identifier) @name.definition.function
operator: "<-"
rhs: (function_definition)
) @definition.function
(binary_operator
lhs: (identifier) @name.definition.function
operator: "="
rhs: (function_definition)
) @definition.function
(call
function: (identifier) @name.reference.call
) @reference.call
(call
function: (namespace_operator
rhs: (identifier) @name.reference.call
)
) @reference.call

View File

@@ -0,0 +1,12 @@
(list
.
(symbol) @reference._define
(#match? @reference._define "^(define|define/contract)$")
.
(list
.
(symbol) @name.definition.function) @definition.function)
(list
.
(symbol) @name.reference.call)

View File

@@ -0,0 +1,64 @@
; Method definitions
(
(comment)* @doc
.
[
(method
name: (_) @name.definition.method) @definition.method
(singleton_method
name: (_) @name.definition.method) @definition.method
]
(#strip! @doc "^#\\s*")
(#select-adjacent! @doc @definition.method)
)
(alias
name: (_) @name.definition.method) @definition.method
(setter
(identifier) @ignore)
; Class definitions
(
(comment)* @doc
.
[
(class
name: [
(constant) @name.definition.class
(scope_resolution
name: (_) @name.definition.class)
]) @definition.class
(singleton_class
value: [
(constant) @name.definition.class
(scope_resolution
name: (_) @name.definition.class)
]) @definition.class
]
(#strip! @doc "^#\\s*")
(#select-adjacent! @doc @definition.class)
)
; Module definitions
(
(module
name: [
(constant) @name.definition.module
(scope_resolution
name: (_) @name.definition.module)
]) @definition.module
)
; Calls
(call method: (identifier) @name.reference.call) @reference.call
(
[(identifier) (constant)] @name.reference.call @reference.call
(#is-not? local)
(#not-match? @name.reference.call "^(lambda|load|require|require_relative|__FILE__|__LINE__)$")
)

View File

@@ -0,0 +1,60 @@
; ADT definitions
(struct_item
name: (type_identifier) @name.definition.class) @definition.class
(enum_item
name: (type_identifier) @name.definition.class) @definition.class
(union_item
name: (type_identifier) @name.definition.class) @definition.class
; type aliases
(type_item
name: (type_identifier) @name.definition.class) @definition.class
; method definitions
(declaration_list
(function_item
name: (identifier) @name.definition.method) @definition.method)
; function definitions
(function_item
name: (identifier) @name.definition.function) @definition.function
; trait definitions
(trait_item
name: (type_identifier) @name.definition.interface) @definition.interface
; module definitions
(mod_item
name: (identifier) @name.definition.module) @definition.module
; macro definitions
(macro_definition
name: (identifier) @name.definition.macro) @definition.macro
; references
(call_expression
function: (identifier) @name.reference.call) @reference.call
(call_expression
function: (field_expression
field: (field_identifier) @name.reference.call)) @reference.call
(macro_invocation
macro: (identifier) @name.reference.call) @reference.call
; implementations
(impl_item
trait: (type_identifier) @name.reference.implementation) @reference.implementation
(impl_item
type: (type_identifier) @name.reference.implementation
!trait) @reference.implementation

View File

@@ -0,0 +1,43 @@
;; Method and Function declarations
(contract_declaration (_
(function_definition
name: (identifier) @name.definition.function) @definition.method))
(source_file
(function_definition
name: (identifier) @name.definition.function) @definition.function)
;; Contract, struct, enum and interface declarations
(contract_declaration
name: (identifier) @name.definition.class) @definition.class
(interface_declaration
name: (identifier) @name.definition.interface) @definition.interface
(library_declaration
name: (identifier) @name.definition.class) @definition.interface
(struct_declaration name: (identifier) @name.definition.class) @definition.class
(enum_declaration name: (identifier) @name.definition.class) @definition.class
(event_definition name: (identifier) @name.definition.class) @definition.class
;; Function calls
(call_expression (expression (identifier)) @name.reference.call ) @reference.call
(call_expression
(expression (member_expression
property: (_) @name.reference.method ))) @reference.call
;; Log emit
(emit_statement name: (_) @name.reference.class) @reference.class
;; Inheritance
(inheritance_specifier
ancestor: (user_defined_type (_) @name.reference.class . )) @reference.class
;; Imports ( note that unknown is not standardised )
(import_directive
import_name: (_) @name.reference.module ) @reference.unknown

View File

@@ -0,0 +1,51 @@
(class_declaration
name: (type_identifier) @name.definition.class) @definition.class
(protocol_declaration
name: (type_identifier) @name.definition.interface) @definition.interface
(class_declaration
(class_body
[
(function_declaration
name: (simple_identifier) @name.definition.method
)
(subscript_declaration
(parameter (simple_identifier) @name.definition.method)
)
(init_declaration "init" @name.definition.method)
(deinit_declaration "deinit" @name.definition.method)
]
)
) @definition.method
(protocol_declaration
(protocol_body
[
(protocol_function_declaration
name: (simple_identifier) @name.definition.method
)
(subscript_declaration
(parameter (simple_identifier) @name.definition.method)
)
(init_declaration "init" @name.definition.method)
]
)
) @definition.method
(class_declaration
(class_body
[
(property_declaration
(pattern (simple_identifier) @name.definition.property)
)
]
)
) @definition.property
(property_declaration
(pattern (simple_identifier) @name.definition.property)
) @definition.property
(function_declaration
name: (simple_identifier) @name.definition.function) @definition.function

View File

@@ -0,0 +1,20 @@
(assignment
key: "LABEL"
(value
(content) @name.definition.label)) @definition.label
(assignment
key: "GOTO"
(value
(content) @name.reference.label)) @reference.label
(assignment
key: "ENV"
(env_var) @name.definition.variable) @definition.variable
(match
key: "ENV"
(env_var) @name.reference.variable) @reference.variable
(var_sub
(env_var) @name.reference.variable) @reference.variable

View File

@@ -883,3 +883,15 @@
max_tokens: 128000
top_p: 0.95
- name: cohere_chat/command-a-03-2025
examples_as_sys_msg: true
- name: openrouter/cohere/command-a-03-2025
examples_as_sys_msg: true
- name: gemini/gemma-3-27b-it
use_system_prompt: false
- name: openrouter/google/gemma-3-27b-it:free
use_system_prompt: false

View File

@@ -23,6 +23,29 @@ cog.out(text)
]]]-->
### main branch
- Big upgrade in [programming languages supported](https://aider.chat/docs/languages.html) by adopting [tree-sitter-language-pack](https://github.com/Goldziher/tree-sitter-language-pack/).
- 130 new languages with linter support.
- 20 new languages with repo-map support.
- Added `/think-tokens` command to set thinking token budget with support for human-readable formats (8k, 10.5k, 0.5M).
- Added `/reasoning-effort` command to control model reasoning level.
- The `/think-tokens` and `/reasoning-effort` commands display current settings when called without arguments.
- Display of thinking token budget and reasoning effort in model information.
- Changed `--thinking-tokens` argument to accept string values with human-readable formats.
- Added `--auto-accept-architect` flag (default: true) to automatically accept changes from architect coder format without confirmation.
- Added support for `cohere_chat/command-a-03-2025` and `gemini/gemma-3-27b-it`
- The bare `/drop` command now preserves original read-only files provided via args.read.
- Fixed a bug where default model would be set by deprecated `--shortcut` switches even when already specified in the command line.
- Improved AutoCompleter to require 3 characters for autocompletion to reduce noise.
- Aider wrote 72% of the code in this release.
### Aider v0.76.2
- Fixed handling of JSONDecodeError when loading model cache file.
- Fixed handling of GitCommandError when retrieving git user configuration.
- Aider wrote 75% of the code in this release.
### Aider v0.76.1
- Added ignore_permission_denied option to file watcher to prevent errors when accessing restricted files, by Yutaka Matsubara.

View File

@@ -256,4 +256,4 @@
date: 2024-12-22
versions: 0.69.2.dev
seconds_per_case: 12.2
total_cost: 0.0000
total_cost: 0.0000

View File

@@ -727,4 +727,30 @@
date: 2025-03-07
versions: 0.75.3.dev
seconds_per_case: 137.4
total_cost: 0
total_cost: 0
- dirname: 2025-03-13-20-46-30--cmda-whole
test_cases: 225
model: command-a-03-2025
edit_format: whole
commit_hash: 024b913-dirty
pass_rate_1: 2.2
pass_rate_2: 4.9
pass_num_1: 5
pass_num_2: 11
percent_cases_well_formed: 100.0
error_outputs: 38
num_malformed_responses: 0
num_with_malformed_responses: 0
user_asks: 231
lazy_comments: 0
syntax_errors: 0
indentation_errors: 0
exhausted_context_windows: 0
test_timeouts: 2
total_tests: 225
command: aider --model cohere_chat/command-a-03-2025
date: 2025-03-13
versions: 0.76.3.dev
seconds_per_case: 106.3
total_cost: 0.0000

File diff suppressed because it is too large Load Diff

View File

@@ -98,6 +98,9 @@
## Use architect edit format for the main chat
#architect: false
## Enable/disable automatic acceptance of architect changes (default: True)
#auto-accept-architect: true
## Specify the model to use for commit messages and chat history summarization (default depends on --model)
#weak-model: xxx

View File

@@ -87,6 +87,9 @@
## Use architect edit format for the main chat
#AIDER_ARCHITECT=
## Enable/disable automatic acceptance of architect changes (default: True)
#AIDER_AUTO_ACCEPT_ARCHITECT=true
## Specify the model to use for commit messages and chat history summarization (default depends on --model)
#AIDER_WEAK_MODEL=

View File

@@ -445,6 +445,9 @@ cog.out("```\n")
- name: claude-3-sonnet-20240229
weak_model_name: claude-3-5-haiku-20241022
- name: cohere_chat/command-a-03-2025
examples_as_sys_msg: true
- name: command-r-08-2024
weak_model_name: command-r-08-2024
use_repo_map: true
@@ -576,6 +579,9 @@ cog.out("```\n")
edit_format: diff
use_repo_map: true
- name: gemini/gemma-3-27b-it
use_system_prompt: false
- name: gpt-3.5-turbo
weak_model_name: gpt-4o-mini
reminder: sys
@@ -872,6 +878,9 @@ cog.out("```\n")
editor_model_name: openrouter/anthropic/claude-3.7-sonnet
editor_edit_format: editor-diff
- name: openrouter/cohere/command-a-03-2025
examples_as_sys_msg: true
- name: openrouter/deepseek/deepseek-chat
edit_format: diff
use_repo_map: true
@@ -932,6 +941,9 @@ cog.out("```\n")
editor_model_name: openrouter/deepseek/deepseek-r1:free
editor_edit_format: editor-diff
- name: openrouter/google/gemma-3-27b-it:free
use_system_prompt: false
- name: openrouter/meta-llama/llama-3-70b-instruct
edit_format: diff
weak_model_name: openrouter/meta-llama/llama-3-70b-instruct

View File

@@ -152,6 +152,9 @@ cog.outl("```")
## Use architect edit format for the main chat
#architect: false
## Enable/disable automatic acceptance of architect changes (default: True)
#auto-accept-architect: true
## Specify the model to use for commit messages and chat history summarization (default depends on --model)
#weak-model: xxx

View File

@@ -127,6 +127,9 @@ cog.outl("```")
## Use architect edit format for the main chat
#AIDER_ARCHITECT=
## Enable/disable automatic acceptance of architect changes (default: True)
#AIDER_AUTO_ACCEPT_ARCHITECT=true
## Specify the model to use for commit messages and chat history summarization (default depends on --model)
#AIDER_WEAK_MODEL=

View File

@@ -30,6 +30,7 @@ usage: aider [-h] [--model] [--openai-api-key] [--anthropic-api-key]
[--model-metadata-file] [--alias] [--reasoning-effort]
[--thinking-tokens] [--verify-ssl | --no-verify-ssl]
[--timeout] [--edit-format] [--architect]
[--auto-accept-architect | --no-auto-accept-architect]
[--weak-model] [--editor-model] [--editor-edit-format]
[--show-model-warnings | --no-show-model-warnings]
[--max-chat-history-tokens]
@@ -191,6 +192,14 @@ Aliases:
Use architect edit format for the main chat
Environment variable: `AIDER_ARCHITECT`
### `--auto-accept-architect`
Enable/disable automatic acceptance of architect changes (default: True)
Default: True
Environment variable: `AIDER_AUTO_ACCEPT_ARCHITECT`
Aliases:
- `--auto-accept-architect`
- `--no-auto-accept-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`

View File

@@ -249,12 +249,10 @@ tr:hover { background-color: #f5f5f5; }
</style>
<table>
<tr><th>Model Name</th><th class='right'>Total Tokens</th><th class='right'>Percent</th></tr>
<tr><td>anthropic/claude-3-7-sonnet-20250219</td><td class='right'>1,063,669</td><td class='right'>92.4%</td></tr>
<tr><td>openrouter/deepseek/deepseek-r1</td><td class='right'>40,786</td><td class='right'>3.5%</td></tr>
<tr><td>o3-mini</td><td class='right'>32,728</td><td class='right'>2.8%</td></tr>
<tr><td>gpt-4o</td><td class='right'>8,092</td><td class='right'>0.7%</td></tr>
<tr><td>groq/REDACTED</td><td class='right'>3,914</td><td class='right'>0.3%</td></tr>
<tr><td>fireworks_ai/accounts/fireworks/models/deepseek-r1</td><td class='right'>1,873</td><td class='right'>0.2%</td></tr>
<tr><td>anthropic/claude-3-7-sonnet-20250219</td><td class='right'>1,755,049</td><td class='right'>96.4%</td></tr>
<tr><td>openrouter/anthropic/claude-3.7-sonnet</td><td class='right'>45,196</td><td class='right'>2.5%</td></tr>
<tr><td>fireworks_ai/accounts/fireworks/models/deepseek-r1</td><td class='right'>17,585</td><td class='right'>1.0%</td></tr>
<tr><td>cohere_chat/REDACTED</td><td class='right'>1,893</td><td class='right'>0.1%</td></tr>
</table>
{: .note :}

View File

@@ -55,55 +55,208 @@ cog.out(get_supported_languages_md())
| Language | File extension | Repo map | Linter |
|:--------:|:--------------:|:--------:|:------:|
| actionscript | .as | | ✓ |
| ada | .adb | | ✓ |
| ada | .ads | | ✓ |
| agda | .agda | | ✓ |
| arduino | .ino | ✓ | ✓ |
| asm | .asm | | ✓ |
| asm | .s | | ✓ |
| astro | .astro | | ✓ |
| bash | .bash | | ✓ |
| bash | .sh | | ✓ |
| bash | .zsh | | ✓ |
| beancount | .bean | | ✓ |
| bibtex | .bib | | ✓ |
| bicep | .bicep | | ✓ |
| bitbake | .bb | | ✓ |
| bitbake | .bbappend | | ✓ |
| bitbake | .bbclass | | ✓ |
| c | .c | ✓ | ✓ |
| commonlisp | .cl | | ✓ |
| c | .h | | ✓ |
| cairo | .cairo | | ✓ |
| capnp | .capnp | | ✓ |
| chatito | .chatito | ✓ | ✓ |
| clarity | .clar | | ✓ |
| clojure | .clj | | ✓ |
| clojure | .cljc | | ✓ |
| clojure | .cljs | | ✓ |
| clojure | .edn | | ✓ |
| cmake | .cmake | | ✓ |
| cmake | CMakeLists.txt | | ✓ |
| commonlisp | .cl | ✓ | ✓ |
| commonlisp | .lisp | ✓ | ✓ |
| cpon | .cpon | | ✓ |
| cpp | .cc | ✓ | ✓ |
| cpp | .cpp | ✓ | ✓ |
| cpp | .cxx | ✓ | ✓ |
| cpp | .h++ | ✓ | ✓ |
| cpp | .hpp | ✓ | ✓ |
| cpp | .hxx | ✓ | ✓ |
| csharp | .cs | ✓ | ✓ |
| css | .css | | ✓ |
| dockerfile | .dockerfile | | ✓ |
| dot | .dot | | ✓ |
| csv | .csv | | ✓ |
| cuda | .cu | | ✓ |
| cuda | .cuh | | ✓ |
| d | .d | ✓ | ✓ |
| dart | .dart | ✓ | ✓ |
| dockerfile | Dockerfile | | ✓ |
| dtd | .dtd | | ✓ |
| elisp | .el | ✓ | ✓ |
| elixir | .ex | ✓ | ✓ |
| elixir | .exs | ✓ | ✓ |
| elm | .elm | ✓ | ✓ |
| embedded_template | .et | | ✓ |
| erlang | .erl | | ✓ |
| erlang | .hrl | | ✓ |
| fennel | .fnl | | ✓ |
| firrtl | .fir | | ✓ |
| fish | .fish | | ✓ |
| fortran | .f | | ✓ |
| fortran | .f03 | | ✓ |
| fortran | .f08 | | ✓ |
| fortran | .f90 | | ✓ |
| fortran | .f95 | | ✓ |
| func | .fc | | ✓ |
| gdscript | .gd | | ✓ |
| gitattributes | .gitattributes | | ✓ |
| gitcommit | .gitcommit | | ✓ |
| gitignore | .gitignore | | ✓ |
| gleam | .gleam | ✓ | ✓ |
| glsl | .frag | | ✓ |
| glsl | .glsl | | ✓ |
| glsl | .vert | | ✓ |
| gn | .gn | | ✓ |
| gn | .gni | | ✓ |
| go | .go | ✓ | ✓ |
| gomod | .gomod | | ✓ |
| gomod | go.mod | | ✓ |
| gosum | go.sum | | ✓ |
| groovy | .groovy | | ✓ |
| gstlaunch | .launch | | ✓ |
| hack | .hack | | ✓ |
| hare | .ha | | ✓ |
| haskell | .hs | | ✓ |
| haxe | .hx | | ✓ |
| hcl | .hcl | ✓ | ✓ |
| hcl | .tf | ✓ | ✓ |
| hcl | .tfvars | ✓ | ✓ |
| heex | .heex | | ✓ |
| hlsl | .hlsl | | ✓ |
| html | .htm | | ✓ |
| html | .html | | ✓ |
| hyprlang | .hypr | | ✓ |
| ispc | .ispc | | ✓ |
| janet | .janet | | ✓ |
| java | .java | ✓ | ✓ |
| javascript | .js | ✓ | ✓ |
| javascript | .jsx | ✓ | ✓ |
| javascript | .mjs | ✓ | ✓ |
| jsdoc | .jsdoc | | ✓ |
| json | .json | | ✓ |
| jsonnet | .jsonnet | | ✓ |
| jsonnet | .libsonnet | | ✓ |
| julia | .jl | | ✓ |
| kconfig | Kconfig | | ✓ |
| kdl | .kdl | | ✓ |
| kotlin | .kt | ✓ | ✓ |
| lua | .lua | | ✓ |
| kotlin | .kts | | ✓ |
| latex | .cls | | ✓ |
| latex | .sty | | ✓ |
| latex | .tex | | ✓ |
| linkerscript | .ld | | ✓ |
| llvm | .ll | | ✓ |
| lua | .lua | ✓ | ✓ |
| luadoc | .luadoc | | ✓ |
| luap | .luap | | ✓ |
| luau | .luau | | ✓ |
| magik | .magik | | ✓ |
| make | .mk | | ✓ |
| make | Makefile | | ✓ |
| markdown | .markdown | | ✓ |
| markdown | .md | | ✓ |
| objc | .m | | ✓ |
| matlab | .m | | ✓ |
| matlab | .mat | | ✓ |
| mermaid | .mermaid | | ✓ |
| meson | meson.build | | ✓ |
| ninja | .ninja | | ✓ |
| nix | .nix | | ✓ |
| nqc | .nqc | | ✓ |
| objc | .mm | | ✓ |
| odin | .odin | | ✓ |
| org | .org | | ✓ |
| pascal | .pas | | ✓ |
| pascal | .pp | | ✓ |
| pem | .pem | | ✓ |
| perl | .pl | | ✓ |
| perl | .pm | | ✓ |
| pgn | .pgn | | ✓ |
| php | .php | ✓ | ✓ |
| po | .po | | ✓ |
| po | .pot | | ✓ |
| pony | .pony | ✓ | ✓ |
| powershell | .ps1 | | ✓ |
| powershell | .psm1 | | ✓ |
| printf | .printf | | ✓ |
| prisma | .prisma | | ✓ |
| properties | .properties | ✓ | ✓ |
| proto | .proto | | ✓ |
| psv | .psv | | ✓ |
| purescript | .purs | | ✓ |
| pymanifest | MANIFEST.in | | ✓ |
| python | .py | ✓ | ✓ |
| r | .R | | ✓ |
| r | .r | | ✓ |
| regex | .regex | | ✓ |
| qmldir | qmldir | | ✓ |
| qmljs | .qml | | ✓ |
| r | .R | | ✓ |
| r | .r | ✓ | ✓ |
| racket | .rkt | ✓ | ✓ |
| re2c | .re2c | | ✓ |
| readline | .inputrc | | ✓ |
| requirements | requirements.txt | | ✓ |
| ron | .ron | | ✓ |
| rst | .rst | | ✓ |
| ruby | .rb | ✓ | ✓ |
| rust | .rs | ✓ | ✓ |
| scala | .sc | | ✓ |
| scala | .scala | | ✓ |
| scheme | .scm | | ✓ |
| scheme | .ss | | ✓ |
| scss | .scss | | ✓ |
| smali | .smali | | ✓ |
| smithy | .smithy | | ✓ |
| solidity | .sol | ✓ | ✓ |
| sparql | .rq | | ✓ |
| sql | .sql | | ✓ |
| sqlite | .sqlite | | ✓ |
| squirrel | .nut | | ✓ |
| starlark | .bzl | | ✓ |
| starlark | BUILD | | ✓ |
| starlark | WORKSPACE | | ✓ |
| svelte | .svelte | | ✓ |
| swift | .swift | ✓ | ✓ |
| tablegen | .td | | ✓ |
| tcl | .tcl | | ✓ |
| thrift | .thrift | | ✓ |
| toml | .toml | | ✓ |
| tsq | .tsq | | ✓ |
| tsv | .tsv | | ✓ |
| twig | .twig | | ✓ |
| typescript | .ts | ✓ | ✓ |
| typescript | .tsx | ✓ | ✓ |
| yaml | .yaml | | ✓ |
| typst | .typ | | ✓ |
| udev | .rules | ✓ | ✓ |
| ungrammar | .ungram | | ✓ |
| uxntal | .tal | | ✓ |
| verilog | .sv | | ✓ |
| verilog | .v | | ✓ |
| vhdl | .vhd | | ✓ |
| vhdl | .vhdl | | ✓ |
| vim | .vim | | ✓ |
| vim | .vimrc | | ✓ |
| vue | .vue | | ✓ |
| wgsl | .wgsl | | ✓ |
| xcompose | .XCompose | | ✓ |
| xml | .svg | | ✓ |
| xml | .xml | | ✓ |
| xml | .xsl | | ✓ |
| yuck | .yuck | | ✓ |
| zig | .zig | | ✓ |
<!--[[[end]]]-->

View File

@@ -41,11 +41,11 @@ The model also has to successfully apply all its changes to the source file with
<thead style="background-color: #f2f2f2;">
<tr>
<th style="padding: 8px; text-align: left;">Model</th>
<th style="padding: 8px; text-align: center;">Percent completed correctly</th>
<th style="padding: 8px; text-align: center;">Percent correct</th>
<th style="padding: 8px; text-align: center;">Percent using correct edit format</th>
<th style="padding: 8px; text-align: left;">Command</th>
<th style="padding: 8px; text-align: center;">Edit format</th>
<th style="padding: 8px; text-align: center;">Total Cost</th>
<th style="padding: 8px; text-align: center;">Cost</th>
</tr>
</thead>
<tbody>
@@ -88,6 +88,14 @@ The model also has to successfully apply all its changes to the source file with
td:nth-child(3), td:nth-child(4) {
font-size: 12px;
}
/* Hide command and edit format columns on mobile */
@media screen and (max-width: 767px) {
th:nth-child(4), td:nth-child(4), /* Command column */
th:nth-child(5), td:nth-child(5) { /* Edit format column */
display: none;
}
}
</style>
@@ -116,6 +124,6 @@ mod_dates = [get_last_modified_date(file) for file in files]
latest_mod_date = max(mod_dates)
cog.out(f"{latest_mod_date.strftime('%B %d, %Y.')}")
]]]-->
March 07, 2025.
March 13, 2025.
<!--[[[end]]]-->
</p>

View File

@@ -47,12 +47,14 @@ cog.out(get_help_md())
| **/paste** | Paste image/text from the clipboard into the chat. Optionally provide a name for the image. |
| **/quit** | Exit the application |
| **/read-only** | Add files to the chat that are for reference only, or turn added files to read-only |
| **/reasoning-effort** | Set the reasoning effort level (values: number or low/medium/high depending on model) |
| **/report** | Report a problem by opening a GitHub Issue |
| **/reset** | Drop all files and clear the chat history |
| **/run** | Run a shell command and optionally add the output to the chat (alias: !) |
| **/save** | Save commands to a file that can reconstruct the current chat session's files |
| **/settings** | Print out the current settings |
| **/test** | Run a shell command and add the output to the chat on non-zero exit code |
| **/think-tokens** | Set the thinking token budget (supports formats like 8096, 8k, 10.5k, 0.5M) |
| **/tokens** | Report on the number of tokens used by the current chat context |
| **/undo** | Undo the last git commit if it was done by aider |
| **/voice** | Record and transcribe voice input |

View File

@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --no-strip-extras --constraint=requirements/common-constraints.txt --output-file=tmp.requirements.txt requirements/requirements.in
aiohappyeyeballs==2.5.0
aiohappyeyeballs==2.6.1
# via
# -c requirements/common-constraints.txt
# aiohttp
@@ -22,7 +22,7 @@ anyio==4.8.0
# httpx
# openai
# watchfiles
attrs==25.1.0
attrs==25.2.0
# via
# -c requirements/common-constraints.txt
# aiohttp
@@ -98,7 +98,7 @@ gitpython==3.1.44
# via
# -c requirements/common-constraints.txt
# -r requirements/requirements.in
grep-ast==0.7.2
grep-ast==0.8.1
# via
# -c requirements/common-constraints.txt
# -r requirements/requirements.in
@@ -115,7 +115,7 @@ httpx==0.28.1
# -c requirements/common-constraints.txt
# litellm
# openai
huggingface-hub==0.29.2
huggingface-hub==0.29.3
# via
# -c requirements/common-constraints.txt
# tokenizers
@@ -156,7 +156,7 @@ jsonschema-specifications==2024.10.1
# via
# -c requirements/common-constraints.txt
# jsonschema
litellm==1.63.5
litellm==1.63.7
# via
# -c requirements/common-constraints.txt
# -r requirements/requirements.in
@@ -198,7 +198,7 @@ numpy==1.26.4
# -c requirements/common-constraints.txt
# scipy
# soundfile
openai==1.65.5
openai==1.66.3
# via
# -c requirements/common-constraints.txt
# litellm

View File

@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --no-strip-extras --output-file=requirements/common-constraints.txt requirements/requirements.in requirements/requirements-browser.in requirements/requirements-dev.in requirements/requirements-help.in requirements/requirements-playwright.in
aiohappyeyeballs==2.5.0
aiohappyeyeballs==2.6.1
# via aiohttp
aiohttp==3.11.13
# via
@@ -18,7 +18,7 @@ anyio==4.8.0
# httpx
# openai
# watchfiles
attrs==25.1.0
attrs==25.2.0
# via
# aiohttp
# jsonschema
@@ -116,7 +116,7 @@ greenlet==3.1.1
# via
# playwright
# sqlalchemy
grep-ast==0.7.2
grep-ast==0.8.1
# via -r requirements/requirements.in
h11==0.14.0
# via httpcore
@@ -127,7 +127,7 @@ httpx==0.28.1
# litellm
# llama-index-core
# openai
huggingface-hub[inference]==0.29.2
huggingface-hub[inference]==0.29.3
# via
# llama-index-embeddings-huggingface
# sentence-transformers
@@ -174,7 +174,7 @@ jsonschema-specifications==2024.10.1
# via jsonschema
kiwisolver==1.4.8
# via matplotlib
litellm==1.63.5
litellm==1.63.7
# via -r requirements/requirements.in
llama-index-core==0.12.23.post2
# via
@@ -236,7 +236,7 @@ numpy==1.26.4
# soundfile
# streamlit
# transformers
openai==1.65.5
openai==1.66.3
# via litellm
packaging==24.2
# via
@@ -417,9 +417,9 @@ soundfile==0.13.1
# via -r requirements/requirements.in
soupsieve==2.6
# via beautifulsoup4
sqlalchemy[asyncio]==2.0.38
sqlalchemy[asyncio]==2.0.39
# via llama-index-core
streamlit==1.43.1
streamlit==1.43.2
# via -r requirements/requirements-browser.in
sympy==1.13.3
# via torch
@@ -494,7 +494,7 @@ urllib3==2.3.0
# via
# mixpanel
# requests
uv==0.6.5
uv==0.6.6
# via -r requirements/requirements-dev.in
virtualenv==20.29.3
# via pre-commit

View File

@@ -4,7 +4,7 @@ altair==5.5.0
# via
# -c requirements/common-constraints.txt
# streamlit
attrs==25.1.0
attrs==25.2.0
# via
# -c requirements/common-constraints.txt
# jsonschema
@@ -123,7 +123,7 @@ smmap==5.0.2
# via
# -c requirements/common-constraints.txt
# gitdb
streamlit==1.43.1
streamlit==1.43.2
# via
# -c requirements/common-constraints.txt
# -r requirements/requirements-browser.in

View File

@@ -205,7 +205,7 @@ tzdata==2025.1
# via
# -c requirements/common-constraints.txt
# pandas
uv==0.6.5
uv==0.6.6
# via
# -c requirements/common-constraints.txt
# -r requirements/requirements-dev.in

View File

@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --no-strip-extras --constraint=requirements/common-constraints.txt --output-file=requirements/requirements-help.txt requirements/requirements-help.in
aiohappyeyeballs==2.5.0
aiohappyeyeballs==2.6.1
# via
# -c requirements/common-constraints.txt
# aiohttp
@@ -21,7 +21,7 @@ anyio==4.8.0
# via
# -c requirements/common-constraints.txt
# httpx
attrs==25.1.0
attrs==25.2.0
# via
# -c requirements/common-constraints.txt
# aiohttp
@@ -88,7 +88,7 @@ httpx==0.28.1
# via
# -c requirements/common-constraints.txt
# llama-index-core
huggingface-hub[inference]==0.29.2
huggingface-hub[inference]==0.29.3
# via
# -c requirements/common-constraints.txt
# llama-index-embeddings-huggingface
@@ -226,7 +226,7 @@ sniffio==1.3.1
# via
# -c requirements/common-constraints.txt
# anyio
sqlalchemy[asyncio]==2.0.38
sqlalchemy[asyncio]==2.0.39
# via
# -c requirements/common-constraints.txt
# llama-index-core

View File

@@ -6,6 +6,8 @@ Only add new items not already listed.
Do NOT edit or update existing history entries.
Do NOT add duplicate entries for changes that have existing history entries.
Don't add entries for changes which may have been later undone, removed or superseded.
End each bullet with a period.
If the change was made by someone other than Paul Gauthier note it at the end of the bullet point as ", by XXX."

152
scripts/redact-cast.py Executable file
View File

@@ -0,0 +1,152 @@
#!/usr/bin/env python3
import json
import os
import re
import sys
# Speed up factor for the recording
SPEEDUP = 1.25
# Regular expression to match ANSI escape sequences
ANSI_ESCAPE_PATTERN = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|\([0-9A-Z=])")
def strip_ansi(text):
"""Remove ANSI escape sequences from text"""
return ANSI_ESCAPE_PATTERN.sub("", text)
def process_file(input_path, output_path):
"""
Process an asciinema cast v2 file to filter out certain sections based on ANSI cursor commands.
Format: First line is a JSON header. Subsequent lines are JSON arrays: [timestamp, "o", "text"]
If a text field contains "\u001b[ROW;COL]H" followed by "Atuin", skip it and all subsequent
records until finding a text with "\u001b[ROW;(COL-1)H".
Maintains consistent timestamps by:
1. Not advancing time during skip sections
2. Compressing any long gaps to 0.5 seconds maximum
"""
skip_mode = False
target_pattern = None
ansi_pattern = re.compile(r"\u001b\[(\d+);(\d+)H")
is_first_line = True
last_timestamp = 0.0
time_offset = 0.0 # Accumulator for time to subtract
max_gap = 0.5 # Maximum allowed time gap between events
with (
open(input_path, "r", encoding="utf-8") as infile,
open(output_path, "w", encoding="utf-8") as outfile,
):
for line in infile:
# Process the header (first line)
if is_first_line:
try:
header = json.loads(line)
if "env" in header:
del header["env"]
outfile.write(json.dumps(header) + "\n")
except json.JSONDecodeError:
# If we can't parse the header, keep it as is
outfile.write(line)
is_first_line = False
continue
# Parse the JSON record
try:
record = json.loads(line)
if not isinstance(record, list) or len(record) != 3 or record[1] != "o":
# If not a valid record, just write it out
outfile.write(line)
continue
current_timestamp = float(record[0])
text = record[2] # The text content
# If we're not in skip mode, check if we need to enter it
if not skip_mode:
# First check for cursor positioning command
if "\u001b[" in text:
match = ansi_pattern.search(text)
if match and "Atuin" in strip_ansi(text):
row = match.group(1)
col = int(match.group(2))
# Create pattern for the ending sequence
target_pattern = f"\u001b[{row};{col - 1}H"
skip_mode = True
# Start tracking time to subtract
skip_start_time = current_timestamp
continue # Skip this record
# If we're not skipping, write the record with adjusted timestamp
# First, adjust for skipped sections
adjusted_timestamp = current_timestamp - time_offset
# Then, check if there's a long gap to compress
if last_timestamp > 0:
time_gap = adjusted_timestamp - last_timestamp
if time_gap > max_gap:
# Compress the gap and add the excess to time_offset
excess_time = time_gap - max_gap
time_offset += excess_time
adjusted_timestamp -= excess_time
# Ensure timestamps never go backward
adjusted_timestamp = max(adjusted_timestamp, last_timestamp)
last_timestamp = adjusted_timestamp
# Apply speedup factor to the timestamp
record[0] = adjusted_timestamp / SPEEDUP
outfile.write(json.dumps(record) + "\n")
# If we're in skip mode, check if we should exit it
else:
if target_pattern in text:
skip_mode = False
# Calculate how much time to subtract from future timestamps
time_offset += current_timestamp - skip_start_time
# Add a 0.5 second pause after each skip section
last_timestamp += 0.5
# Write this record with adjusted timestamp
adjusted_timestamp = current_timestamp - time_offset
# Check if there's a long gap to compress
if last_timestamp > 0:
time_gap = adjusted_timestamp - last_timestamp
if time_gap > max_gap:
# Compress the gap and add the excess to time_offset
excess_time = time_gap - max_gap
time_offset += excess_time
adjusted_timestamp -= excess_time
# Ensure timestamps never go backward
adjusted_timestamp = max(adjusted_timestamp, last_timestamp)
last_timestamp = adjusted_timestamp
# Apply speedup factor to the timestamp
record[0] = adjusted_timestamp / SPEEDUP
outfile.write(json.dumps(record) + "\n")
# Otherwise we're still in skip mode, don't write anything
except json.JSONDecodeError:
# If we can't parse the line as JSON, include it anyway
outfile.write(line)
if __name__ == "__main__":
if len(sys.argv) != 3:
print(f"Usage: {os.path.basename(sys.argv[0])} input_file output_file")
sys.exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
if not os.path.exists(input_file):
print(f"Error: Input file '{input_file}' does not exist")
sys.exit(1)
process_file(input_file, output_file)
print(f"Processed {input_file} -> {output_file}")

145
scripts/tsl_pack_langs.py Executable file
View File

@@ -0,0 +1,145 @@
#!/usr/bin/env python3
import json
import os
import sys
import time
import requests
def get_default_branch(owner, repo):
"""Get the default branch of a GitHub repository using the API."""
api_url = f"https://api.github.com/repos/{owner}/{repo}"
try:
response = requests.get(api_url)
response.raise_for_status()
return response.json().get("default_branch")
except requests.exceptions.RequestException:
return None
def try_download_tags(owner, repo, branch, directory, output_path):
"""Try to download tags.scm from a specific branch."""
base_url = f"https://raw.githubusercontent.com/{owner}/{repo}/{branch}"
if directory:
tags_url = f"{base_url}/{directory}/queries/tags.scm"
else:
tags_url = f"{base_url}/queries/tags.scm"
try:
response = requests.get(tags_url)
response.raise_for_status()
# Save the file
with open(output_path, "w") as f:
f.write(response.text)
return True
except requests.exceptions.RequestException:
return False
def main():
# Path to the language definitions file
lang_def_path = "../../tmp/tree-sitter-language-pack/sources/language_definitions.json"
# Path to store the tags.scm files
output_dir = "aider/queries/tree-sitter-language-pack"
# Create the output directory if it doesn't exist
os.makedirs(output_dir, exist_ok=True)
# Common branch names to try if API fails and config branch doesn't work
common_branches = ["main", "master", "dev", "develop"]
try:
# Load the language definitions
with open(lang_def_path, "r") as f:
lang_defs = json.load(f)
except Exception as e:
print(f"Error loading language definitions: {e}")
sys.exit(1)
print(f"Found {len(lang_defs)} language definitions")
# Process each language
successes = 0
total = len(lang_defs)
for lang, config in lang_defs.items():
# Extract repo URL from the config
repo_url = config.get("repo")
print(f"Processing {lang} ({repo_url})...")
if not repo_url:
print(f"Skipping {lang}: No repository URL found")
continue
directory = config.get("directory", "")
# Parse the GitHub repository URL
if "github.com" not in repo_url:
print(f"Skipping {lang}: Not a GitHub repository")
continue
# Extract the owner and repo name from the URL
parts = repo_url.rstrip("/").split("/")
if len(parts) < 5:
print(f"Skipping {lang}: Invalid GitHub URL format")
continue
owner = parts[-2]
repo = parts[-1]
# Create output directory and set output file path
os.makedirs(output_dir, exist_ok=True)
output_file = os.path.join(output_dir, f"{lang}-tags.scm")
# Skip if file already exists
if os.path.exists(output_file):
print(f"Skipping {lang}: tags.scm already exists")
successes += 1
continue
# Try branches in this order:
# 1. Branch specified in the config
# 2. Default branch from GitHub API
# 3. Common branch names (main, master, etc.)
branches_to_try = []
# 1. Branch from config (if specified)
config_branch = config.get("branch")
if config_branch:
branches_to_try.append(config_branch)
# 2. Default branch from GitHub API
default_branch = get_default_branch(owner, repo)
if default_branch and default_branch not in branches_to_try:
branches_to_try.append(default_branch)
# 3. Add common branch names
for branch in common_branches:
if branch not in branches_to_try:
branches_to_try.append(branch)
# Try each branch
success = False
for branch in branches_to_try:
if try_download_tags(owner, repo, branch, directory, output_file):
print(f"Successfully downloaded tags for {lang} (branch: {branch})")
success = True
successes += 1
break
if not success:
print(f"Failed to download tags for {lang} after trying all branches")
# Be nice to GitHub's API
time.sleep(0.1)
print(f"All language tags processed. Downloaded {successes}/{total} successfully.")
if __name__ == "__main__":
main()

View File

@@ -66,9 +66,7 @@ def check_main_branch_up_to_date():
# Function to check if we can push to the origin repository
def check_ok_to_push():
print("Checking if it's ok to push to origin repository...")
result = subprocess.run(["git", "push", "--dry-run", "origin"], capture_output=True, text=True)
print(result.stdout)
print(result.stderr)
result = subprocess.run(["git", "push", "--dry-run", "origin"])
if result.returncode != 0:
print("Error: Cannot push to origin repository.")

View File

@@ -37,7 +37,9 @@ class TestCoder(unittest.TestCase):
repo.git.commit("-m", "init")
# YES!
io = InputOutput(yes=True)
# Use a completely mocked IO object instead of a real one
io = MagicMock()
io.confirm_ask = MagicMock(return_value=True)
coder = Coder.create(self.GPT35, None, io, fnames=["added.txt"])
self.assertTrue(coder.allowed_to_edit("added.txt"))
@@ -1059,6 +1061,112 @@ This command will print 'Hello, World!' to the console."""
sanity_check_messages(coder.cur_messages)
self.assertEqual(coder.cur_messages[-1]["role"], "assistant")
def test_architect_coder_auto_accept_true(self):
with GitTemporaryDirectory():
io = InputOutput(yes=True)
io.confirm_ask = MagicMock(return_value=True)
# Create an ArchitectCoder with auto_accept_architect=True
with patch("aider.coders.architect_coder.AskCoder.__init__", return_value=None):
from aider.coders.architect_coder import ArchitectCoder
coder = ArchitectCoder()
coder.io = io
coder.main_model = self.GPT35
coder.auto_accept_architect = True
coder.verbose = False
coder.total_cost = 0
coder.cur_messages = []
coder.done_messages = []
coder.summarizer = MagicMock()
coder.summarizer.too_big.return_value = False
# Mock editor_coder creation and execution
mock_editor = MagicMock()
with patch("aider.coders.architect_coder.Coder.create", return_value=mock_editor):
# Set partial response content
coder.partial_response_content = "Make these changes to the code"
# Call reply_completed
coder.reply_completed()
# Verify that confirm_ask was not called (auto-accepted)
io.confirm_ask.assert_not_called()
# Verify that editor coder was created and run
mock_editor.run.assert_called_once()
def test_architect_coder_auto_accept_false_confirmed(self):
with GitTemporaryDirectory():
io = InputOutput(yes=False)
io.confirm_ask = MagicMock(return_value=True)
# Create an ArchitectCoder with auto_accept_architect=False
with patch("aider.coders.architect_coder.AskCoder.__init__", return_value=None):
from aider.coders.architect_coder import ArchitectCoder
coder = ArchitectCoder()
coder.io = io
coder.main_model = self.GPT35
coder.auto_accept_architect = False
coder.verbose = False
coder.total_cost = 0
coder.cur_messages = []
coder.done_messages = []
coder.summarizer = MagicMock()
coder.summarizer.too_big.return_value = False
coder.cur_messages = []
coder.done_messages = []
coder.summarizer = MagicMock()
coder.summarizer.too_big.return_value = False
# Mock editor_coder creation and execution
mock_editor = MagicMock()
with patch("aider.coders.architect_coder.Coder.create", return_value=mock_editor):
# Set partial response content
coder.partial_response_content = "Make these changes to the code"
# Call reply_completed
coder.reply_completed()
# Verify that confirm_ask was called
io.confirm_ask.assert_called_once_with("Edit the files?")
# Verify that editor coder was created and run
mock_editor.run.assert_called_once()
def test_architect_coder_auto_accept_false_rejected(self):
with GitTemporaryDirectory():
io = InputOutput(yes=False)
io.confirm_ask = MagicMock(return_value=False)
# Create an ArchitectCoder with auto_accept_architect=False
with patch("aider.coders.architect_coder.AskCoder.__init__", return_value=None):
from aider.coders.architect_coder import ArchitectCoder
coder = ArchitectCoder()
coder.io = io
coder.main_model = self.GPT35
coder.auto_accept_architect = False
coder.verbose = False
coder.total_cost = 0
# Mock editor_coder creation and execution
mock_editor = MagicMock()
with patch("aider.coders.architect_coder.Coder.create", return_value=mock_editor):
# Set partial response content
coder.partial_response_content = "Make these changes to the code"
# Call reply_completed
coder.reply_completed()
# Verify that confirm_ask was called
io.confirm_ask.assert_called_once_with("Edit the files?")
# Verify that editor coder was NOT created or run
# (because user rejected the changes)
mock_editor.run.assert_not_called()
if __name__ == "__main__":
unittest.main()

View File

@@ -1283,6 +1283,38 @@ class TestCommands(TestCase):
# Verify the file was not added
self.assertEqual(len(coder.abs_fnames), 0)
def test_cmd_think_tokens(self):
io = InputOutput(pretty=False, fancy_input=False, yes=True)
coder = Coder.create(self.GPT35, None, io)
commands = Commands(io, coder)
# Test with various formats
test_values = {
"8k": 8192, # 8 * 1024
"10.5k": 10752, # 10.5 * 1024
"512k": 524288, # 0.5 * 1024 * 1024
}
for input_value, expected_tokens in test_values.items():
with mock.patch.object(io, "tool_output") as mock_tool_output:
commands.cmd_think_tokens(input_value)
# Check that the model's thinking tokens were updated
self.assertEqual(
coder.main_model.extra_params["thinking"]["budget_tokens"], expected_tokens
)
# Check that the tool output shows the correct value with format
# Use the actual input_value (not normalized) in the assertion
mock_tool_output.assert_any_call(
f"Set thinking token budget to {expected_tokens:,} tokens ({input_value})."
)
# Test with no value provided - should display current value
with mock.patch.object(io, "tool_output") as mock_tool_output:
commands.cmd_think_tokens("")
mock_tool_output.assert_any_call(mock.ANY) # Just verify it calls tool_output
def test_cmd_add_aiderignored_file(self):
with GitTemporaryDirectory():
repo = git.Repo()
@@ -1722,6 +1754,213 @@ class TestCommands(TestCase):
del coder
del commands
def test_reset_with_original_read_only_files(self):
with GitTemporaryDirectory() as repo_dir:
io = InputOutput(pretty=False, fancy_input=False, yes=True)
coder = Coder.create(self.GPT35, None, io)
# Create test files
orig_read_only = Path(repo_dir) / "orig_read_only.txt"
orig_read_only.write_text("Original read-only file")
added_file = Path(repo_dir) / "added_file.txt"
added_file.write_text("Added file")
added_read_only = Path(repo_dir) / "added_read_only.txt"
added_read_only.write_text("Added read-only file")
# Initialize commands with original read-only files
commands = Commands(io, coder, original_read_only_fnames=[str(orig_read_only)])
# Add files to the chat
coder.abs_read_only_fnames.add(str(orig_read_only))
coder.abs_fnames.add(str(added_file))
coder.abs_read_only_fnames.add(str(added_read_only))
# Add some messages to the chat history
coder.cur_messages = [{"role": "user", "content": "Test message"}]
coder.done_messages = [{"role": "assistant", "content": "Test response"}]
# Verify initial state
self.assertEqual(len(coder.abs_fnames), 1)
self.assertEqual(len(coder.abs_read_only_fnames), 2)
self.assertEqual(len(coder.cur_messages), 1)
self.assertEqual(len(coder.done_messages), 1)
# Test reset command
commands.cmd_reset("")
# Verify that original read-only file is preserved
# but other files and messages are cleared
self.assertEqual(len(coder.abs_fnames), 0)
self.assertEqual(len(coder.abs_read_only_fnames), 1)
self.assertIn(str(orig_read_only), coder.abs_read_only_fnames)
self.assertNotIn(str(added_read_only), coder.abs_read_only_fnames)
# Chat history should be cleared
self.assertEqual(len(coder.cur_messages), 0)
self.assertEqual(len(coder.done_messages), 0)
def test_reset_with_no_original_read_only_files(self):
with GitTemporaryDirectory() as repo_dir:
io = InputOutput(pretty=False, fancy_input=False, yes=True)
coder = Coder.create(self.GPT35, None, io)
# Create test files
added_file = Path(repo_dir) / "added_file.txt"
added_file.write_text("Added file")
added_read_only = Path(repo_dir) / "added_read_only.txt"
added_read_only.write_text("Added read-only file")
# Initialize commands with no original read-only files
commands = Commands(io, coder)
# Add files to the chat
coder.abs_fnames.add(str(added_file))
coder.abs_read_only_fnames.add(str(added_read_only))
# Add some messages to the chat history
coder.cur_messages = [{"role": "user", "content": "Test message"}]
coder.done_messages = [{"role": "assistant", "content": "Test response"}]
# Verify initial state
self.assertEqual(len(coder.abs_fnames), 1)
self.assertEqual(len(coder.abs_read_only_fnames), 1)
self.assertEqual(len(coder.cur_messages), 1)
self.assertEqual(len(coder.done_messages), 1)
# Test reset command
commands.cmd_reset("")
# Verify that all files and messages are cleared
self.assertEqual(len(coder.abs_fnames), 0)
self.assertEqual(len(coder.abs_read_only_fnames), 0)
self.assertEqual(len(coder.cur_messages), 0)
self.assertEqual(len(coder.done_messages), 0)
def test_cmd_reasoning_effort(self):
io = InputOutput(pretty=False, fancy_input=False, yes=True)
coder = Coder.create(self.GPT35, None, io)
commands = Commands(io, coder)
# Test with numeric values
with mock.patch.object(io, "tool_output") as mock_tool_output:
commands.cmd_reasoning_effort("0.8")
mock_tool_output.assert_any_call("Set reasoning effort to 0.8")
# Test with text values (low/medium/high)
for effort_level in ["low", "medium", "high"]:
with mock.patch.object(io, "tool_output") as mock_tool_output:
commands.cmd_reasoning_effort(effort_level)
mock_tool_output.assert_any_call(f"Set reasoning effort to {effort_level}")
# Check model's reasoning effort was updated
with mock.patch.object(coder.main_model, "set_reasoning_effort") as mock_set_effort:
commands.cmd_reasoning_effort("0.5")
mock_set_effort.assert_called_once_with("0.5")
# Test with no value provided - should display current value
with mock.patch.object(io, "tool_output") as mock_tool_output:
commands.cmd_reasoning_effort("")
mock_tool_output.assert_any_call("Current reasoning effort: high")
def test_drop_with_original_read_only_files(self):
with GitTemporaryDirectory() as repo_dir:
io = InputOutput(pretty=False, fancy_input=False, yes=True)
coder = Coder.create(self.GPT35, None, io)
# Create test files
orig_read_only = Path(repo_dir) / "orig_read_only.txt"
orig_read_only.write_text("Original read-only file")
added_file = Path(repo_dir) / "added_file.txt"
added_file.write_text("Added file")
added_read_only = Path(repo_dir) / "added_read_only.txt"
added_read_only.write_text("Added read-only file")
# Initialize commands with original read-only files
commands = Commands(io, coder, original_read_only_fnames=[str(orig_read_only)])
# Add files to the chat
coder.abs_read_only_fnames.add(str(orig_read_only))
coder.abs_fnames.add(str(added_file))
coder.abs_read_only_fnames.add(str(added_read_only))
# Verify initial state
self.assertEqual(len(coder.abs_fnames), 1)
self.assertEqual(len(coder.abs_read_only_fnames), 2)
# Test bare drop command
with mock.patch.object(io, "tool_output") as mock_tool_output:
commands.cmd_drop("")
mock_tool_output.assert_called_with(
"Dropping all files from the chat session except originally read-only files."
)
# Verify that original read-only file is preserved, but other files are dropped
self.assertEqual(len(coder.abs_fnames), 0)
self.assertEqual(len(coder.abs_read_only_fnames), 1)
self.assertIn(str(orig_read_only), coder.abs_read_only_fnames)
self.assertNotIn(str(added_read_only), coder.abs_read_only_fnames)
def test_drop_specific_original_read_only_file(self):
with GitTemporaryDirectory() as repo_dir:
io = InputOutput(pretty=False, fancy_input=False, yes=True)
coder = Coder.create(self.GPT35, None, io)
# Create test file
orig_read_only = Path(repo_dir) / "orig_read_only.txt"
orig_read_only.write_text("Original read-only file")
# Initialize commands with original read-only files
commands = Commands(io, coder, original_read_only_fnames=[str(orig_read_only)])
# Add file to the chat
coder.abs_read_only_fnames.add(str(orig_read_only))
# Verify initial state
self.assertEqual(len(coder.abs_read_only_fnames), 1)
# Test specific drop command
commands.cmd_drop("orig_read_only.txt")
# Verify that the original read-only file is dropped when specified explicitly
self.assertEqual(len(coder.abs_read_only_fnames), 0)
def test_drop_with_no_original_read_only_files(self):
with GitTemporaryDirectory() as repo_dir:
io = InputOutput(pretty=False, fancy_input=False, yes=True)
coder = Coder.create(self.GPT35, None, io)
# Create test files
added_file = Path(repo_dir) / "added_file.txt"
added_file.write_text("Added file")
added_read_only = Path(repo_dir) / "added_read_only.txt"
added_read_only.write_text("Added read-only file")
# Initialize commands with no original read-only files
commands = Commands(io, coder)
# Add files to the chat
coder.abs_fnames.add(str(added_file))
coder.abs_read_only_fnames.add(str(added_read_only))
# Verify initial state
self.assertEqual(len(coder.abs_fnames), 1)
self.assertEqual(len(coder.abs_read_only_fnames), 1)
# Test bare drop command
with mock.patch.object(io, "tool_output") as mock_tool_output:
commands.cmd_drop("")
mock_tool_output.assert_called_with("Dropping all files from the chat session.")
# Verify that all files are dropped
self.assertEqual(len(coder.abs_fnames), 0)
self.assertEqual(len(coder.abs_read_only_fnames), 0)
def test_cmd_load_with_switch_coder(self):
with GitTemporaryDirectory() as repo_dir:
io = InputOutput(pretty=False, fancy_input=False, yes=True)

View File

@@ -160,6 +160,51 @@ class TestModels(unittest.TestCase):
self.assertEqual(model.name, "github/o1-preview")
self.assertEqual(model.use_temperature, False)
def test_parse_token_value(self):
# Create a model instance to test the parse_token_value method
model = Model("gpt-4")
# Test integer inputs
self.assertEqual(model.parse_token_value(8096), 8096)
self.assertEqual(model.parse_token_value(1000), 1000)
# Test string inputs
self.assertEqual(model.parse_token_value("8096"), 8096)
# Test k/K suffix (kilobytes)
self.assertEqual(model.parse_token_value("8k"), 8 * 1024)
self.assertEqual(model.parse_token_value("8K"), 8 * 1024)
self.assertEqual(model.parse_token_value("10.5k"), 10.5 * 1024)
self.assertEqual(model.parse_token_value("0.5K"), 0.5 * 1024)
# Test m/M suffix (megabytes)
self.assertEqual(model.parse_token_value("1m"), 1 * 1024 * 1024)
self.assertEqual(model.parse_token_value("1M"), 1 * 1024 * 1024)
self.assertEqual(model.parse_token_value("0.5M"), 0.5 * 1024 * 1024)
# Test with spaces
self.assertEqual(model.parse_token_value(" 8k "), 8 * 1024)
# Test conversion from other types
self.assertEqual(model.parse_token_value(8.0), 8)
def test_set_thinking_tokens(self):
# Test that set_thinking_tokens correctly sets the tokens with different formats
model = Model("gpt-4")
# Test with integer
model.set_thinking_tokens(8096)
self.assertEqual(model.extra_params["thinking"]["budget_tokens"], 8096)
self.assertFalse(model.use_temperature)
# Test with string
model.set_thinking_tokens("10k")
self.assertEqual(model.extra_params["thinking"]["budget_tokens"], 10 * 1024)
# Test with decimal value
model.set_thinking_tokens("0.5M")
self.assertEqual(model.extra_params["thinking"]["budget_tokens"], 0.5 * 1024 * 1024)
@patch("aider.models.check_pip_install_extra")
def test_check_for_dependencies_bedrock(self, mock_check_pip):
"""Test that check_for_dependencies calls check_pip_install_extra for Bedrock models"""

View File

@@ -282,74 +282,142 @@ class TestRepoMapTypescript(unittest.TestCase):
class TestRepoMapAllLanguages(unittest.TestCase):
def setUp(self):
self.GPT35 = Model("gpt-3.5-turbo")
self.fixtures_dir = Path(__file__).parent.parent / "fixtures" / "languages"
def test_get_repo_map_all_languages(self):
language_files = {
"c": ("c", "main"),
"cpp": ("cpp", "main"),
"elixir": ("ex", "Greeter"),
"java": ("java", "Greeting"),
"javascript": ("js", "Person"),
"kotlin": ("kt", "Greeting"),
# "ocaml": ("ml", "Greeter"), # not supported in tsl-pack (yet?)
"php": ("php", "greet"),
"python": ("py", "Person"),
# "ql": ("ql", "greet"), # not supported in tsl-pack (yet?)
"ruby": ("rb", "greet"),
"rust": ("rs", "Person"),
"typescript": ("ts", "greet"),
"tsx": ("tsx", "UserProps"),
"csharp": ("cs", "IGreeter"),
"elisp": ("el", "greeter"),
"elm": ("elm", "Person"),
"go": ("go", "Greeter"),
"hcl": ("tf", "aws_vpc"),
}
def test_language_c(self):
self._test_language_repo_map("c", "c", "main")
fixtures_dir = Path(__file__).parent.parent / "fixtures" / "languages"
def test_language_cpp(self):
self._test_language_repo_map("cpp", "cpp", "main")
for lang, key_symbol in language_files.items():
# Get the fixture file path and name based on language
fixture_dir = fixtures_dir / lang
ext, key_symbol = language_files[lang]
filename = f"test.{ext}"
fixture_path = fixture_dir / filename
self.assertTrue(
fixture_path.exists(), f"Fixture file missing for {lang}: {fixture_path}"
def test_language_d(self):
self._test_language_repo_map("d", "d", "main")
def test_language_dart(self):
self._test_language_repo_map("dart", "dart", "Person")
def test_language_elixir(self):
self._test_language_repo_map("elixir", "ex", "Greeter")
def test_language_gleam(self):
self._test_language_repo_map("gleam", "gleam", "greet")
def test_language_java(self):
self._test_language_repo_map("java", "java", "Greeting")
def test_language_javascript(self):
self._test_language_repo_map("javascript", "js", "Person")
def test_language_kotlin(self):
self._test_language_repo_map("kotlin", "kt", "Greeting")
def test_language_lua(self):
self._test_language_repo_map("lua", "lua", "greet")
# "ocaml": ("ml", "Greeter"), # not supported in tsl-pack (yet?)
def test_language_php(self):
self._test_language_repo_map("php", "php", "greet")
def test_language_python(self):
self._test_language_repo_map("python", "py", "Person")
# "ql": ("ql", "greet"), # not supported in tsl-pack (yet?)
def test_language_ruby(self):
self._test_language_repo_map("ruby", "rb", "greet")
def test_language_rust(self):
self._test_language_repo_map("rust", "rs", "Person")
def test_language_typescript(self):
self._test_language_repo_map("typescript", "ts", "greet")
def test_language_tsx(self):
self._test_language_repo_map("tsx", "tsx", "UserProps")
def test_language_csharp(self):
self._test_language_repo_map("csharp", "cs", "IGreeter")
def test_language_elisp(self):
self._test_language_repo_map("elisp", "el", "greeter")
def test_language_elm(self):
self._test_language_repo_map("elm", "elm", "Person")
def test_language_go(self):
self._test_language_repo_map("go", "go", "Greeter")
def test_language_hcl(self):
self._test_language_repo_map("hcl", "tf", "aws_vpc")
def test_language_arduino(self):
self._test_language_repo_map("arduino", "ino", "setup")
def test_language_chatito(self):
self._test_language_repo_map("chatito", "chatito", "intent")
def test_language_commonlisp(self):
self._test_language_repo_map("commonlisp", "lisp", "greet")
def test_language_pony(self):
self._test_language_repo_map("pony", "pony", "Greeter")
def test_language_properties(self):
self._test_language_repo_map("properties", "properties", "database.url")
def test_language_r(self):
self._test_language_repo_map("r", "r", "calculate")
def test_language_racket(self):
self._test_language_repo_map("racket", "rkt", "greet")
def test_language_solidity(self):
self._test_language_repo_map("solidity", "sol", "SimpleStorage")
def test_language_swift(self):
self._test_language_repo_map("swift", "swift", "Greeter")
def test_language_udev(self):
self._test_language_repo_map("udev", "rules", "USB_DRIVER")
def _test_language_repo_map(self, lang, key, symbol):
"""Helper method to test repo map generation for a specific language."""
# Get the fixture file path and name based on language
fixture_dir = self.fixtures_dir / lang
filename = f"test.{key}"
fixture_path = fixture_dir / filename
self.assertTrue(fixture_path.exists(), f"Fixture file missing for {lang}: {fixture_path}")
# Read the fixture content
with open(fixture_path, "r", encoding="utf-8") as f:
content = f.read()
with GitTemporaryDirectory() as temp_dir:
test_file = os.path.join(temp_dir, filename)
with open(test_file, "w", encoding="utf-8") as f:
f.write(content)
io = InputOutput()
repo_map = RepoMap(main_model=self.GPT35, root=temp_dir, io=io)
other_files = [test_file]
result = repo_map.get_repo_map([], other_files)
dump(lang)
dump(result)
self.assertGreater(len(result.strip().splitlines()), 1)
# Check if the result contains all the expected files and symbols
self.assertIn(
filename, result, f"File for language {lang} not found in repo map: {result}"
)
self.assertIn(
symbol,
result,
f"Key symbol '{symbol}' for language {lang} not found in repo map: {result}",
)
# Read the fixture content
with open(fixture_path, "r", encoding="utf-8") as f:
content = f.read()
with GitTemporaryDirectory() as temp_dir:
test_file = os.path.join(temp_dir, filename)
with open(test_file, "w", encoding="utf-8") as f:
f.write(content)
io = InputOutput()
repo_map = RepoMap(main_model=self.GPT35, root=temp_dir, io=io)
other_files = [filename]
result = repo_map.get_repo_map([], other_files)
dump(lang)
dump(result)
self.assertGreater(len(result.strip().splitlines()), 1)
# Check if the result contains all the expected files and symbols
self.assertIn(
filename, result, f"File for language {lang} not found in repo map: {result}"
)
self.assertIn(
key_symbol,
result,
(
f"Key symbol '{key_symbol}' for language {lang} not found in repo map:"
f" {result}"
),
)
# close the open cache files, so Windows won't error
del repo_map
# close the open cache files, so Windows won't error
del repo_map
def test_repo_map_sample_code_base(self):
# Path to the sample code base

View File

@@ -0,0 +1,21 @@
// Simple Arduino sketch
void setup() {
// Initialize serial communication
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
// Main code that runs repeatedly
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
Serial.println("Blinking LED");
}
// A custom function
int calculateDelay(int baseDelay, int multiplier) {
return baseDelay * multiplier;
}

View File

@@ -4,3 +4,18 @@ int main() {
printf("Hello, World!\n");
return 0;
}
#include <stdio.h>
/**
* The main entry point of the program
* @return 0 on success
*/
int main(int argc, char **argv) {
printf("Hello, World!\n");
return 0;
}
// Helper function
void print_message(const char *message) {
printf("%s\n", message);
}

View File

@@ -0,0 +1,20 @@
%[intent]('training': '60', 'testing': '40')
~[greet]
~[greet] @[name?] ~[endPolite?]
%[name]('training': '50', 'testing': '50')
John
Anna
Bob
Sarah
~[greet]
hi
hello
hey
greetings
~[endPolite]
please
thanks
thank you

View File

@@ -0,0 +1,17 @@
;;; Simple Common Lisp example
(defun greet (name)
"Return a greeting string for NAME."
(format nil "Hello, ~a!" name))
(defvar *greeting-style* 'formal
"Style to use for greetings.")
(defclass person ()
((name :initarg :name :accessor person-name)
(age :initarg :age :accessor person-age))
(:documentation "A class representing a person."))
(defmethod print-object ((obj person) stream)
(print-unreadable-object (obj stream :type t)
(format stream "~a, age ~a" (person-name obj) (person-age obj))))

26
tests/fixtures/languages/d/test.d vendored Normal file
View File

@@ -0,0 +1,26 @@
import std.stdio;
/**
* Main function for the D language test file.
*/
void main() {
writeln("Hello, D language!");
auto greeter = new Greeter("World");
writeln(greeter.greet());
}
/**
* A simple greeter class in D
*/
class Greeter {
private string name;
this(string name) {
this.name = name;
}
string greet() {
return "Hello, " ~ name ~ "!";
}
}

21
tests/fixtures/languages/dart/test.dart vendored Normal file
View File

@@ -0,0 +1,21 @@
// A simple Dart class for testing ctags detection
class Person {
String name;
int age;
Person(this.name, this.age);
void greet() {
print('Hello, my name is $name and I am $age years old.');
}
bool isAdult() {
return age >= 18;
}
}
void main() {
var person = Person('John', 30);
person.greet();
print('Is adult: ${person.isAdult()}');
}

View File

@@ -36,3 +36,24 @@ main =
div [ class "greeting" ]
[ text (greet Formal defaultPerson)
]
module Main exposing (..)
-- Define a Person type
type alias Person =
{ name : String
, age : Int
}
-- Create a person
newPerson : String -> Int -> Person
newPerson name age =
{ name = name
, age = age
}
-- Main function
main =
let
person = newPerson "John Doe" 30
in
text ("Hello, " ++ person.name)

View File

@@ -0,0 +1,10 @@
import gleam/io
pub fn greet(name: String) -> String {
"Hello, " <> name <> "!"
}
pub fn main() {
greet("World")
|> io.println
}

25
tests/fixtures/languages/lua/test.lua vendored Normal file
View File

@@ -0,0 +1,25 @@
-- Simple Lua module with a greeting function
-- Person class definition
local Person = {}
Person.__index = Person
function Person.new(name)
local self = setmetatable({}, Person)
self.name = name
return self
end
-- Main greeting function to be detected by ctags
function greet(person)
return "Hello, " .. person.name .. "!"
end
-- Example usage
local p = Person.new("World")
print(greet(p))
return {
Person = Person,
greet = greet
}

View File

@@ -0,0 +1,8 @@
class Greeter
fun greet(name: String): String =>
"Hello, " + name + "!"
actor Main
new create(env: Env) =>
let greeter = Greeter
env.out.print(greeter.greet("Pony"))

View File

@@ -0,0 +1,14 @@
# Database Configuration
database.url=jdbc:mysql://localhost:3306/mydb
database.username=admin
database.password=secret
# Application Settings
app.name=My Application
app.version=1.0.0
app.debug=true
# Server Configuration
server.port=8080
server.host=localhost
server.maxConnections=100

17
tests/fixtures/languages/r/test.r vendored Normal file
View File

@@ -0,0 +1,17 @@
# Simple R function for testing repository mapping
calculate <- function(x, y) {
# This function performs a simple calculation
result <- x * y
return(result)
}
# Another function to test detection
process_data <- function(data) {
# Process some data
return(data * 2)
}
# Example usage
sample_data <- c(1, 2, 3, 4, 5)
result <- calculate(10, 5)
processed <- process_data(sample_data)

View File

@@ -0,0 +1,8 @@
#lang racket
;; Define a simple greeting function
(define (greet name)
(string-append "Hello, " name "!"))
;; Example usage
(greet "World")

View File

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleStorage {
uint256 private value;
event ValueChanged(uint256 newValue);
constructor(uint256 initialValue) {
value = initialValue;
}
function setValue(uint256 newValue) public {
value = newValue;
emit ValueChanged(newValue);
}
function getValue() public view returns (uint256) {
return value;
}
}

View File

@@ -0,0 +1,18 @@
// Swift greeting example
class Greeter {
let name: String
init(name: String) {
self.name = name
}
func greet() -> String {
return "Hello, \(name)!"
}
}
// Example usage
func exampleGreeting() {
let greeter = Greeter(name: "World")
print(greeter.greet())
}

View File

@@ -0,0 +1,22 @@
# Define a label for a specific device
LABEL="my_usb_device", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678"
# Reference a label in a GOTO
SUBSYSTEM=="usb", GOTO="my_peripheral"
# Define environment variables
ENV{DEVTYPE}="usb_device"
ENV{USB_DRIVER}="usb-storage"
# Reference environment variables
ENV{DEVTYPE}=="usb_device", SYMLINK+="usb_storage_%k"
# Variable substitution
SYMLINK+="disk/by-label/$env{ID_FS_LABEL}"
# Label for a section of rules
LABEL="my_peripheral"
SUBSYSTEM=="usb", MODE="0666"
# End label
LABEL="end_my_rules"