Compare commits

...

204 Commits

Author SHA1 Message Date
Paul Gauthier
80909e17c7 set version to 0.82.2.dev 2025-04-16 18:16:55 -07:00
Paul Gauthier
52697ea884 version bump to 0.82.1 2025-04-16 18:16:52 -07:00
Paul Gauthier
9f01c8d0d6 no stream main o3 2025-04-16 18:16:33 -07:00
Paul Gauthier
e91d7e74ae copy 2025-04-16 18:12:22 -07:00
Paul Gauthier
20ca0463ea feat: Disable streaming for o3 models due to token issue 2025-04-16 18:12:04 -07:00
Paul Gauthier
5e40f469bf copy 2025-04-16 18:10:15 -07:00
Paul Gauthier
7f28d63c33 add o4-mini (high) 2025-04-16 17:24:55 -07:00
Paul Gauthier (aider)
bb1fa24971 feat: Add o4-mini model settings for openai, openrouter, and azure 2025-04-16 17:24:14 -07:00
Paul Gauthier
ffbbaa06d7 chore: Comment out reasoning_effort extra_params 2025-04-16 17:24:13 -07:00
Paul Gauthier (aider)
14e1b96f05 feat: Add azure/gpt-4.1-mini and azure/gpt-4.1 models 2025-04-16 15:45:41 -07:00
Paul Gauthier (aider)
d8c781b66b Feat: Add azure/o3 model settings 2025-04-16 15:44:57 -07:00
Paul Gauthier
2fbec8545c feat: Enable examples_as_sys_msg and set reasoning_effort to high 2025-04-16 15:44:56 -07:00
Paul Gauthier (aider)
b66901fc75 Feat: Add openai/o3 and openrouter/openai/o3 model settings 2025-04-16 15:00:43 -07:00
Paul Gauthier
d569bca520 cleanup 2025-04-16 15:00:32 -07:00
Paul Gauthier
efbefc669f add o3 2025-04-16 14:58:04 -07:00
Paul Gauthier (aider)
24805ff85d fix: Use $10 increments for cost ticks in leaderboard table 2025-04-14 22:02:11 -07:00
Paul Gauthier (aider)
8b917d5716 Refactor: Swap Select and Detail tabs in leaderboard UI 2025-04-14 21:27:45 -07:00
Paul Gauthier (aider)
3502f335ec style: Apply linter to udiff_coder.py 2025-04-14 21:27:10 -07:00
Paul Gauthier (aider)
758979e4f3 fix: Handle git diff prefixes in udiff file paths correctly 2025-04-14 21:27:06 -07:00
Paul Gauthier
8b5fc801da fix: Extract correct filename from unified diff hunk 2025-04-14 21:27:05 -07:00
Paul Gauthier
f5c4214c93 copy 2025-04-14 16:46:57 -07:00
Paul Gauthier
270e84287a copy 2025-04-14 16:32:26 -07:00
Paul Gauthier
daec7cf3f4 set version to 0.82.1.dev 2025-04-14 16:24:22 -07:00
Paul Gauthier
bb42d1e9a5 version bump to 0.82.0 2025-04-14 16:24:19 -07:00
Paul Gauthier (aider)
23f182aab3 feat: Dynamically adjust cost scale and ticks based on visible entries 2025-04-14 16:16:14 -07:00
Paul Gauthier
119fbc995c add gpt-4.1-nano 2025-04-14 16:00:42 -07:00
Paul Gauthier
3081f49179 copy 2025-04-14 15:52:10 -07:00
Paul Gauthier
8cf1874453 added gpt-4.1 and mini 2025-04-14 15:52:06 -07:00
Paul Gauthier (aider)
31b4bd5bcf feat: Apply generic settings for gpt-4.1 and gpt-4.1-mini models 2025-04-14 15:47:01 -07:00
Paul Gauthier
71d1591cc1 cleanup 2025-04-14 15:43:45 -07:00
Paul Gauthier (aider)
134a2d60fe style: Apply linter to patch_flex_coder.py 2025-04-14 15:35:39 -07:00
Paul Gauthier (aider)
152b8912ae refactor: Adapt PatchFlexCoder to use (path, ParsedEdit) tuples 2025-04-14 15:35:35 -07:00
Paul Gauthier (aider)
36f23c101d feat: Add PatchFlexCoder to coders init 2025-04-14 15:33:30 -07:00
Paul Gauthier (aider)
0e40510295 fix: Shorten long comment line in patch_flex_coder.py 2025-04-14 15:32:32 -07:00
Paul Gauthier (aider)
db0d0768d7 style: Remove unused import and reorder imports 2025-04-14 15:32:26 -07:00
Paul Gauthier (aider)
c68cade9f2 Refactor: Use do_replace in PatchFlexCoder instead of flexible_search 2025-04-14 15:32:22 -07:00
Paul Gauthier (aider)
14928727eb refactor: Remove unused remap arg and editblock_strategies var 2025-04-14 15:31:07 -07:00
Paul Gauthier (aider)
67b9345929 fix: Address linting errors in patch_coder and search_replace 2025-04-14 15:30:56 -07:00
Paul Gauthier (aider)
dae1a376a2 fix: Shorten comment to avoid exceeding line length limit. 2025-04-14 15:30:02 -07:00
Paul Gauthier (aider)
1e359f1dcf fix: Improve error message for invalid add file line in diff 2025-04-14 15:29:50 -07:00
Paul Gauthier (aider)
1c54857422 fix: Improve handling of interleaved +/- lines in patch parsing 2025-04-14 15:29:46 -07:00
Paul Gauthier (aider)
0f78a0ac5c style: Fix linting errors in patch_flex_coder.py 2025-04-14 15:29:30 -07:00
Paul Gauthier (aider)
4e1e77890b style: Run linter on patch_flex_coder.py 2025-04-14 15:29:14 -07:00
Paul Gauthier (aider)
5573cdfba1 feat: Create PatchFlexCoder using flexible search and replace for updates 2025-04-14 15:29:10 -07:00
Paul Gauthier
14028d3758 copy 2025-04-14 15:22:22 -07:00
Paul Gauthier
3ab673b398 copy 2025-04-14 15:17:10 -07:00
Paul Gauthier (aider)
861f51f6c3 fix: Define EditResult after PatchAction to resolve flake8 error 2025-04-14 15:08:41 -07:00
Paul Gauthier (aider)
64f5d0d388 refactor: Adapt PatchCoder to return List[Tuple[str, PatchAction]] 2025-04-14 15:08:28 -07:00
Paul Gauthier (aider)
9059af8d5f style: Reorder imports in aider/coders/__init__.py 2025-04-14 15:02:28 -07:00
Paul Gauthier (aider)
c3a543b99d feat: Add PatchCoder to the list of available coders 2025-04-14 15:02:25 -07:00
Paul Gauthier (aider)
c85cd783e5 feat: Use PatchPrompts class in PatchCoder 2025-04-14 15:01:36 -07:00
Paul Gauthier (aider)
af2d241c99 feat: Connect PatchCoder with PatchPrompts 2025-04-14 15:01:22 -07:00
Paul Gauthier (aider)
30839a5273 style: Run linter on patch_prompts.py 2025-04-14 14:58:50 -07:00
Paul Gauthier (aider)
8baa99b7ef refactor: Update PatchPrompts to use V4A diff format 2025-04-14 14:58:46 -07:00
Paul Gauthier
d1e5572343 feat: Add patch prompts for aider coders 2025-04-14 14:52:03 -07:00
Paul Gauthier (aider)
96aa648e17 chore: Fix linting issues: remove unused import, shorten long lines 2025-04-14 14:45:24 -07:00
Paul Gauthier (aider)
1ae5f23dc8 style: Run linter on patch_coder.py 2025-04-14 14:45:14 -07:00
Paul Gauthier (aider)
f565f72679 refactor: Integrate core logic from apply_patch.py into PatchCoder 2025-04-14 14:45:09 -07:00
Paul Gauthier (aider)
78e76648d0 feat: Add openai/gpt-4.1-mini and openrouter/openai/gpt-4.1-mini models 2025-04-14 14:42:20 -07:00
Paul Gauthier
8e1e2210dd feat: Add model settings for gpt-4.1-mini 2025-04-14 14:42:20 -07:00
Paul Gauthier (aider)
e8c43c36d7 fix: Shorten long comment line in patch_coder.py 2025-04-14 14:37:03 -07:00
Paul Gauthier (aider)
97e2a7bae0 fix: Correct spacing in patch_coder.py for accurate matching 2025-04-14 14:36:54 -07:00
Paul Gauthier (aider)
6b75a578ac style: Fix linting errors in patch_coder.py 2025-04-14 14:36:42 -07:00
Paul Gauthier (aider)
8b9238ebc9 style: Run linter on patch_coder.py 2025-04-14 14:36:27 -07:00
Paul Gauthier (aider)
8cc8027b40 feat: Create PatchCoder for applying patch-formatted code edits 2025-04-14 14:36:24 -07:00
Paul Gauthier (aider)
ffb743e108 feat: Add openai/gpt-4.1 and openrouter/openai/gpt-4.1 model settings 2025-04-14 14:26:48 -07:00
Paul Gauthier
0f805752d3 feat: Add gpt-4.1 model settings 2025-04-14 14:26:18 -07:00
Paul Gauthier (aider)
4e9de4d51b style: Add margin below leaderboard title for better spacing 2025-04-14 14:08:52 -07:00
Paul Gauthier (aider)
a4e9539040 feat: Dynamically update leaderboard title based on view mode 2025-04-14 14:04:35 -07:00
Paul Gauthier
0c383dfb11 copy 2025-04-13 13:55:34 -07:00
Paul Gauthier (aider)
11d2b7ca98 style: Adjust tear line height and position in leaderboard table 2025-04-13 13:54:37 -07:00
Paul Gauthier (aider)
e38be2f280 feat: Add dashed tear line to leaderboard bar transition 2025-04-13 13:54:03 -07:00
Paul Gauthier (aider)
febdd3c0d0 style: Extend striped cap on leaderboard bars to 15% 2025-04-13 13:52:32 -07:00
Paul Gauthier (aider)
0b08ca64a8 feat: Add diagonal stripes to large cost bars for hazard pattern 2025-04-13 13:50:59 -07:00
Paul Gauthier (aider)
0f8e7fbd34 feat: Remove cost bar tear line, keep dark end cap 2025-04-13 13:44:23 -07:00
Paul Gauthier (aider)
1a080ba71c feat: Remove numeric labels below cost bars in leaderboard table 2025-04-13 13:43:32 -07:00
Paul Gauthier (aider)
1622531d85 feat: Remove cost exceeded marker from leaderboard table 2025-04-13 13:42:35 -07:00
Paul Gauthier
7d0a9c7233 fix: Adjust cost tear marker position in leaderboards 2025-04-13 13:42:34 -07:00
Paul Gauthier (aider)
53a64c88ad feat: Color the cost bar past the tear marker darker blue 2025-04-13 13:37:56 -07:00
Paul Gauthier (aider)
27b51d51d8 feat: Draw tear across cost bar for exceeded costs on leaderboard 2025-04-13 13:37:01 -07:00
Paul Gauthier
bec35e0538 docs: Shorten "Cost (max $50)" to "Cost" in leaderboards table header 2025-04-13 13:37:00 -07:00
Paul Gauthier (aider)
f65e6a3bb1 feat: Limit cost bar to $50, mark bars exceeding, add tick labels 2025-04-13 13:35:47 -07:00
Paul Gauthier (aider)
fd94f1a5f9 fix: Remove log scale from leaderboard cost column header 2025-04-13 13:34:11 -07:00
Paul Gauthier (aider)
09fc037d4d feat: stop using log-scale for costs on the leaderboard 2025-04-13 13:34:06 -07:00
Paul Gauthier (aider)
cf0e6dac61 style: Set height on table rows instead of min-height on cells 2025-04-13 12:44:02 -07:00
Paul Gauthier (aider)
3b10e3bcb5 style: Use min-height for leaderboard table data cells 2025-04-13 12:43:18 -07:00
Paul Gauthier (aider)
4c17784444 style: Set consistent row height in leaderboards table 2025-04-13 12:41:28 -07:00
Paul Gauthier
6616f0886d copy 2025-04-13 11:59:09 -07:00
Paul Gauthier (aider)
dcafab2764 style: Improve leaderboard layout on narrow screens 2025-04-13 11:58:03 -07:00
Paul Gauthier
3b6146301f fix: Improve leaderboard table layout for better readability 2025-04-13 11:58:02 -07:00
Paul Gauthier
42e09b3c7f docs: Improve leaderboard column header for edit format 2025-04-13 11:52:48 -07:00
Paul Gauthier (aider)
73da42bee6 feat: Use percent_cases_well_formed for leaderboard conform rate 2025-04-13 11:51:24 -07:00
Paul Gauthier (aider)
415b1cf5f0 feat: Update label for conform_rate_2 to be more descriptive 2025-04-13 11:50:45 -07:00
Paul Gauthier (aider)
c011285904 feat: Add % conform and edit format columns to leaderboard table 2025-04-13 11:50:09 -07:00
Paul Gauthier
4314b4fefb copy 2025-04-13 11:22:53 -07:00
Paul Gauthier (aider)
d686f6844d style: Apply left border only to the first column in view mode 2025-04-13 11:08:49 -07:00
Paul Gauthier (aider)
65a0e5f771 style: Apply left border and subtle background to highlighted rows 2025-04-13 11:08:18 -07:00
Paul Gauthier
5ca6d8ce67 style: Change leaderboard highlight color to light yellow 2025-04-13 11:08:17 -07:00
Paul Gauthier (aider)
688c2b9ee5 style: Change leaderboard highlight color to light peach 2025-04-13 10:53:40 -07:00
Paul Gauthier (aider)
271f39505c style: Change view-highlighted background to light yellow 2025-04-13 10:53:11 -07:00
Paul Gauthier (aider)
3e8367ea3b style: Use light green for highlighted leaderboard rows 2025-04-13 10:52:21 -07:00
Paul Gauthier (aider)
67a1e52259 docs: Add kind words from kache (@yacineMTB) 2025-04-13 10:43:24 -07:00
Paul Gauthier
7561687b7b copy 2025-04-13 10:35:27 -07:00
Paul Gauthier
93fc7acbe3 copy 2025-04-13 10:34:33 -07:00
Paul Gauthier (aider)
72dc67950f docs: Fix link to reasoning settings documentation 2025-04-13 10:33:36 -07:00
Paul Gauthier (aider)
e2bebd1d51 docs: Note Grok 3 Mini supports --reasoning-effort flag 2025-04-13 10:33:11 -07:00
Paul Gauthier
03560d3386 docs: Add trailing newline to xai.md 2025-04-13 10:33:10 -07:00
Paul Gauthier (aider)
a3a3303a83 docs: List all Grok-3 and Grok-3-mini models in xai.md 2025-04-13 10:32:42 -07:00
Paul Gauthier
232a6f87d2 docs: Update xAI model names and usage instructions 2025-04-13 10:32:41 -07:00
Paul Gauthier (aider)
ab71ea0a65 feat: Add grok-3-fast and grok-3-mini-fast model configurations 2025-04-13 10:31:53 -07:00
Paul Gauthier (aider)
1302224f39 style: Make close button smaller and more compact 2025-04-13 09:54:18 -07:00
Paul Gauthier (aider)
733bf0dcdf feat: Add close button to hide leaderboard controls container 2025-04-13 09:52:32 -07:00
Paul Gauthier (aider)
4ed48178a9 fix: Improve leaderboard toggle button responsiveness on iOS Safari 2025-04-13 09:50:47 -07:00
Paul Gauthier
8cffb975d9 docs: Clarify Aider's LLM evaluation criteria and add polyglot link 2025-04-13 09:47:32 -07:00
Paul Gauthier
97b18797a4 copy 2025-04-13 09:16:18 -07:00
Paul Gauthier (aider)
579794b265 feat: Show only selected rows in 'View' mode if selections exist 2025-04-13 09:15:00 -07:00
Paul Gauthier (aider)
bea746595e feat: Hide first column in leaderboard table when in 'View' mode 2025-04-13 09:13:42 -07:00
Paul Gauthier (aider)
87711b048a feat: Implement three-state mode (View/Select/Detail) for leaderboard 2025-04-13 09:11:54 -07:00
Paul Gauthier
0b468ebd85 copy 2025-04-13 08:57:33 -07:00
Paul Gauthier
aefc250e30 move 2025-04-13 08:57:12 -07:00
Paul Gauthier (aider)
4a86fea86b refactor: Move script tags to markdown, include only js code 2025-04-13 08:56:36 -07:00
Paul Gauthier (aider)
fe6e2e1ea7 Refactor: Embed leaderboard script using Jekyll include tag 2025-04-13 08:55:44 -07:00
Paul Gauthier (aider)
09d90b9b70 Refactor: Move leaderboard table JS to external file for better caching. 2025-04-13 08:55:14 -07:00
Paul Gauthier
14eb7b46a2 feat: Add leaderboard table javascript file 2025-04-13 08:55:13 -07:00
Paul Gauthier (aider)
66077fe3a4 feat: Implement row highlighting in view mode for leaderboards 2025-04-13 08:52:58 -07:00
Paul Gauthier (aider)
d50cf806db feat: Add row click listener for checkbox toggle in select mode 2025-04-13 08:50:32 -07:00
Paul Gauthier (aider)
95edae9bd1 style: Style active leaderboard mode button with JS, remove CSS rule 2025-04-13 08:48:43 -07:00
Paul Gauthier (aider)
a6c35305ed style: Adjust active mode toggle button colors for contrast 2025-04-13 08:48:00 -07:00
Paul Gauthier (aider)
b382005a4c style: Remove inline background color from "View" button 2025-04-13 08:46:02 -07:00
Paul Gauthier (aider)
a71b90bdd6 feat: Implement toggle buttons for view mode selection 2025-04-13 08:44:49 -07:00
Paul Gauthier (aider)
d4a68c80bc feat: Replace dropdown with segmented button group for view mode 2025-04-13 08:44:36 -07:00
Paul Gauthier (aider)
fcf44cbebe fix: Only apply row-selected class in 'select' mode 2025-04-13 08:41:12 -07:00
Paul Gauthier (aider)
51d8cb063a feat: Simplify leaderboard modes to 'View' and 'Select' 2025-04-13 08:40:30 -07:00
Paul Gauthier (aider)
cdc86565cc Refactor: Update leaderboard dropdown option text for clarity 2025-04-13 08:39:05 -07:00
Paul Gauthier (aider)
1c54907b30 style: Improve leaderboard controls appearance with CSS styling 2025-04-13 08:38:13 -07:00
Paul Gauthier (aider)
b6d4246e18 feat: Replace segmented buttons with dropdown for view mode selection 2025-04-13 08:37:47 -07:00
Paul Gauthier (aider)
cc1a984c7e feat: Replace clear selection button with select all checkbox 2025-04-13 08:35:37 -07:00
Paul Gauthier (aider)
52d39657ab feat: Implement table view modes, row selection, and search filter 2025-04-13 08:33:14 -07:00
Paul Gauthier (aider)
363ec82a48 feat: Implement leaderboard view mode toggle (All/Select/Selected) 2025-04-13 08:32:54 -07:00
Paul Gauthier (aider)
f164b0e3eb style: Adjust font size of numbers in leaderboard bars 2025-04-13 08:12:10 -07:00
Paul Gauthier (aider)
3aaf7a69ec style: Adjust leaderboard number positioning in bar cells 2025-04-13 01:20:41 -07:00
Paul Gauthier (aider)
6d2828bc3c style: Update cost bar color in leaderboards docs 2025-04-13 00:46:57 -07:00
Paul Gauthier (aider)
dd6e2051a8 Style: Improve leaderboard table borders for visual clarity 2025-04-13 00:44:12 -07:00
Paul Gauthier (aider)
ef440972bb Refactor: Remove chart and add margin to post date in leaderboard 2025-04-13 00:42:37 -07:00
Paul Gauthier (aider)
da96888669 style: Hide command column on small screens in leaderboards 2025-04-13 00:41:44 -07:00
Paul Gauthier (aider)
75639059e1 style: Make toggle symbols more subtle by changing their color 2025-04-13 00:40:44 -07:00
Paul Gauthier (aider)
0a15dd311a feat: Use Unicode triangles for leaderboard toggle button 2025-04-13 00:40:19 -07:00
Paul Gauthier (aider)
434a1c6710 feat: Replace +/- with chevron icons for leaderboard details toggle 2025-04-13 00:39:24 -07:00
Paul Gauthier (aider)
f961eecab6 Feat: Add toggleable detail view to leaderboard table 2025-04-12 23:44:43 -07:00
Paul Gauthier (aider)
d33a571f7d Refactor: Remove edit-format column from leaderboards 2025-04-12 23:40:54 -07:00
Paul Gauthier
ea1239efef Docs: Clarify polyglot benchmark measures edits without intervention. 2025-04-12 23:40:53 -07:00
Paul Gauthier (aider)
19c7c7a9dc Docs: Make leaderboards intro text more concise 2025-04-12 23:37:16 -07:00
Paul Gauthier (aider)
49e4af4fab fix: Display '?' for zero or rounded-to-zero costs in leaderboards 2025-04-12 23:32:35 -07:00
Paul Gauthier (aider)
3e27c1bb17 feat: Only add cost ticks if the cost is greater than zero 2025-04-12 23:32:01 -07:00
Paul Gauthier (aider)
0f8d196741 style: Increase font size of leaderboard bar chart numbers 2025-04-12 23:30:29 -07:00
Paul Gauthier
4c45f0e44b style: Improve leaderboard bar chart tick visibility 2025-04-12 23:30:28 -07:00
Paul Gauthier (aider)
e39eef1ed7 style: Align ticks with bottom edge of leaderboard bars 2025-04-12 23:26:21 -07:00
Paul Gauthier
c9c7aea1c4 docs: Improve leaderboard cost visualization and table layout 2025-04-12 23:26:05 -07:00
Paul Gauthier (aider)
18ff9eb2b4 style: Make tick color lighter in leaderboards 2025-04-12 23:23:36 -07:00
Paul Gauthier (aider)
b2f3d2cd84 style: Improve visibility of ticks in leaderboard progress bars 2025-04-12 23:23:03 -07:00
Paul Gauthier (aider)
5e0832cb8b feat: Add percentage ticks to leaderboard percentage columns 2025-04-12 23:21:38 -07:00
Paul Gauthier (aider)
a14c0ccac6 style: Align cost-tick height with bar height in leaderboards 2025-04-12 23:20:56 -07:00
Paul Gauthier (aider)
278f90acdd fix: Add tick at base of cost column bars in leaderboards 2025-04-12 23:20:08 -07:00
Paul Gauthier (aider)
8e8b18e9a9 fix: Align ticks in bar table cells to 0%, 10%, 20%, etc. 2025-04-12 23:18:47 -07:00
Paul Gauthier (aider)
a277d74869 feat: Add dynamic cost ticks to leaderboards page cost bars 2025-04-12 23:14:21 -07:00
Paul Gauthier (aider)
7ca3b6455d feat: Add tick marks to leaderboard % correct and cost columns 2025-04-12 23:14:08 -07:00
Paul Gauthier (aider)
5ec6f69037 feat: Add tick marks to table bar graph cells 2025-04-12 23:13:04 -07:00
Paul Gauthier (aider)
39962ba5eb style: Remove internal cell borders from leaderboards table 2025-04-12 23:10:55 -07:00
Paul Gauthier (aider)
51fa1f9abd Refactor: Remove "Percent using correct edit format" column 2025-04-12 23:10:18 -07:00
Paul Gauthier
47af5d463c docs: Clarify cost column in leaderboards is log scale 2025-04-12 23:10:17 -07:00
Paul Gauthier (aider)
33f0b0b41c fix: Remove invalid Liquid comment from leaderboards page 2025-04-12 23:08:57 -07:00
Paul Gauthier (aider)
48038b1f5e feat: Use log scale for cost bar in leaderboards table 2025-04-12 23:08:28 -07:00
Paul Gauthier (aider)
323698d387 style: Remove box-shadow from bar graph numeric text container 2025-04-12 20:53:06 -07:00
Paul Gauthier (aider)
1f702beb74 style: Improve legibility of numbers in leaderboard table cells 2025-04-12 20:49:12 -07:00
Paul Gauthier
7d34c28af1 style: Reduce height of leaderboard progress bars 2025-04-12 20:47:02 -07:00
Paul Gauthier (aider)
d26be77010 feat: Hide cost bar if cost is 0 or unknown in leaderboards table 2025-04-12 20:45:29 -07:00
Paul Gauthier (aider)
3b96d1bd57 fix: Adjust bar-viz height in leaderboards page CSS 2025-04-12 20:43:07 -07:00
Paul Gauthier (aider)
48fd0e71d5 style: Increase bar height and fix colors in leaderboards 2025-04-12 20:42:58 -07:00
Paul Gauthier
bcb35ccf44 style: Reduce leaderboard bar height for better readability 2025-04-12 20:42:58 -07:00
Paul Gauthier (aider)
a663ff7fa8 style: Make leaderboard bars 2x taller 2025-04-12 20:40:46 -07:00
Paul Gauthier (aider)
813d34a0e9 style: Fix inconsistent bar heights in leaderboards table 2025-04-12 20:40:18 -07:00
Paul Gauthier (aider)
a4074a13c4 fix: Swap colors of leaderboard columns for correct display 2025-04-12 20:25:35 -07:00
Paul Gauthier (aider)
249f329b07 fix: Correct leaderboard bar colors and logic for accuracy 2025-04-12 20:24:51 -07:00
Paul Gauthier (aider)
cf160a8f84 fix: Swap colors of leaderboard columns 2 and 3 2025-04-12 20:23:45 -07:00
Paul Gauthier (aider)
4db963182d feat: Add color variation to cost bars in leaderboards 2025-04-12 20:21:38 -07:00
Paul Gauthier (aider)
199b59fdb9 feat: Improve table-as-bar-graph with color variation based on value 2025-04-12 20:21:08 -07:00
Paul Gauthier (aider)
2d09bfa0f3 feat: Implement dedicated bar element inside table cells for visualization 2025-04-12 20:15:28 -07:00
Paul Gauthier (aider)
729285e8a2 refactor: Move cost column in leaderboards table to be after percent 2025-04-12 20:13:05 -07:00
Paul Gauthier (aider)
afd17bd96a style: Improve leaderboard table styling with padding and bar adjustments 2025-04-12 20:11:09 -07:00
Paul Gauthier (aider)
380d8570dc fix: Remove visible Liquid comment from leaderboard page 2025-04-12 20:09:38 -07:00
Paul Gauthier (aider)
e711eaa810 feat: Add horizontal bar graphs to leaderboard numerical columns 2025-04-12 20:08:35 -07:00
Paul Gauthier
7dfdc2094e refactor: Use EditBlockFencedPrompts directly in EditorDiffFencedPrompts 2025-04-12 20:04:04 -07:00
Paul Gauthier (aider)
838646ac5b refactor: EditorDiffFencedCoder inherits from EditBlockFencedCoder 2025-04-12 19:57:10 -07:00
Paul Gauthier (aider)
507f07575b feat: Add diff-fenced to copy-paste edit format prefixing 2025-04-12 19:55:53 -07:00
Paul Gauthier (aider)
f5e8808770 feat: Add "diff-fenced" to editor edit format options. 2025-04-12 19:55:35 -07:00
Paul Gauthier (aider)
ae5b6e88a5 feat: Enable EditorDiffFencedCoder by adding it to __init__.py 2025-04-12 19:55:10 -07:00
Paul Gauthier (aider)
b45186dde0 feat: Add editor-diff-fenced coder and prompts classes 2025-04-12 19:52:43 -07:00
Paul Gauthier
38be8aa0da copy 2025-04-12 17:12:10 -07:00
Paul Gauthier (aider)
816d4ba206 docs: Add kind words from koleok to README 2025-04-12 17:10:29 -07:00
Paul Gauthier
ede59e4d2a docs: Fix typo in README quote from joseph stalzyn 2025-04-12 17:10:28 -07:00
Paul Gauthier (aider)
ce0931a3c8 docs: Add kind words from users to README 2025-04-12 17:08:37 -07:00
Paul Gauthier
a44e148818 feat: Add go_ahead_tip and rename_with_shell to editblock prompts 2025-04-12 17:04:12 -07:00
Paul Gauthier
71115c6558 feat: Add editor-diff and editor-whole edit formats 2025-04-12 16:44:13 -07:00
Paul Gauthier
8ae837e98b copy 2025-04-12 15:49:42 -07:00
29 changed files with 3611 additions and 1112 deletions

View File

@@ -1,10 +1,19 @@
# Release history
### main branch
### Aider v0.82.0
- Support for GPT 4.1, mini and nano.
- Added new `patch` edit format for OpenAI's GPT-4.1 model.
- Improved support for using architect mode with Gemini 2.5 Pro.
- Added new `editor-diff`, `editor-whole`, and `editor-diff-fenced` edit formats.
- Bugfix for automatically selecting the best edit format to use in architect mode.
- Added support for `grok-3-fast-beta` and `grok-3-mini-fast-beta` models.
- Aider wrote 92% of the code in this release.
### Aider v0.81.3
- Commit messages generated by aider are no longer forced to be entirely lowercase, by Peter Hadlaw.
- Updated default settings for Grok models.
- Aider wrote 64% of the code in this release.
### Aider v0.81.2
@@ -16,14 +25,12 @@
- Fix quoting of values containing '#' in the sample `aider.conf.yml`.
- Add support for Fireworks AI model 'deepseek-v3-0324', by Felix Lisczyk.
- Commit messages generated by aider are now lowercase, by Anton Ödman.
- Aider wrote 64% of the code in this release.
### Aider v0.81.1
- Added support for the `gemini/gemini-2.5-pro-preview-03-25` model.
- Updated the `gemini` alias to point to `gemini/gemini-2.5-pro-preview-03-25`.
- Added the `gemini-exp` alias for `gemini/gemini-2.5-pro-exp-03-25`.
- Aider wrote 87% of the code in this release.
### Aider v0.81.0

View File

@@ -27,13 +27,13 @@ cog.out(text)
<a href="https://github.com/Aider-AI/aider/stargazers"><img alt="GitHub Stars" title="Total number of GitHub stars the Aider project has received"
src="https://img.shields.io/github/stars/Aider-AI/aider?style=flat-square&logo=github&color=f1c40f&labelColor=555555"/></a>
<a href="https://pypi.org/project/aider-chat/"><img alt="PyPI Downloads" title="Total number of installations via pip from PyPI"
src="https://img.shields.io/badge/📦%20Installs-1.9M-2ecc71?style=flat-square&labelColor=555555"/></a>
src="https://img.shields.io/badge/📦%20Installs-2.0M-2ecc71?style=flat-square&labelColor=555555"/></a>
<img alt="Tokens per week" title="Number of tokens processed weekly by Aider users"
src="https://img.shields.io/badge/📈%20Tokens%2Fweek-15B-3498db?style=flat-square&labelColor=555555"/>
<a href="https://openrouter.ai/#options-menu"><img alt="OpenRouter Ranking" title="Aider's ranking among applications on the OpenRouter platform"
src="https://img.shields.io/badge/🏆%20OpenRouter-Top%2020-9b59b6?style=flat-square&labelColor=555555"/></a>
<a href="https://aider.chat/HISTORY.html"><img alt="Singularity" title="Percentage of the new code in Aider's last release written by Aider itself"
src="https://img.shields.io/badge/🔄%20Singularity-86%25-e74c3c?style=flat-square&labelColor=555555"/></a>
src="https://img.shields.io/badge/🔄%20Singularity-92%25-e74c3c?style=flat-square&labelColor=555555"/></a>
<!--[[[end]]]-->
</p>
@@ -140,6 +140,7 @@ See the [installation instructions](https://aider.chat/docs/install.html) and [u
## Kind Words From Users
- *"My life has changed this week. There's finally an AI coding tool that's good enough to keep up with me... Aider... It's going to rock your world."* — [Eric S. Raymond](https://x.com/esrtweet/status/1910809356381413593)
- *"The best free open source AI coding assistant."* — [IndyDevDan](https://youtu.be/YALpX8oOn78)
- *"The best AI coding assistant so far."* — [Matthew Berman](https://www.youtube.com/watch?v=df8afeb1FY8)
- *"Aider ... has easily quadrupled my coding productivity."* — [SOLAR_FIELDS](https://news.ycombinator.com/item?id=36212100)
@@ -169,4 +170,8 @@ See the [installation instructions](https://aider.chat/docs/install.html) and [u
- *"I like aider :)"* — [Chenwei Cui](https://x.com/ccui42/status/1904965344999145698)
- *"Aider is the precision tool of LLM code gen. It is minimal, thoughtful and capable of surgical changes to your codebase all while keeping the developer in control."* — [Reilly Sweetland](https://x.com/rsweetland/status/1904963807237259586)
- *"Cannot believe aider vibe coded a 650 LOC feature across service and cli today in 1 shot."* - [autopoietist](https://discord.com/channels/1131200896827654144/1131200896827654149/1355675042259796101)
- *"Oh no the secret is out! Yes, Aider is the best coding tool around. I highly, highly recommend it to anyone."* — [Joshua D Vander Hook](https://x.com/jodavaho/status/1911154899057795218)
- *"thanks to aider, i have started and finished three personal projects within the last two days"* — [joseph stalzyn](https://x.com/anitaheeder/status/1908338609645904160)
- *"Been using aider as my daily driver for over a year ... I absolutely love the tool, like beyond words."* — [koleok](https://discord.com/channels/1131200896827654144/1273248471394291754/1356727448372252783)
- *"aider is really cool"* — [kache (@yacineMTB)](https://x.com/yacineMTB/status/1911224442430124387)

View File

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

View File

@@ -4,9 +4,11 @@ from .base_coder import Coder
from .context_coder import ContextCoder
from .editblock_coder import EditBlockCoder
from .editblock_fenced_coder import EditBlockFencedCoder
from .editor_diff_fenced_coder import EditorDiffFencedCoder
from .editor_editblock_coder import EditorEditBlockCoder
from .editor_whole_coder import EditorWholeFileCoder
from .help_coder import HelpCoder
from .patch_coder import PatchCoder
from .udiff_coder import UnifiedDiffCoder
from .wholefile_coder import WholeFileCoder
@@ -19,10 +21,12 @@ __all__ = [
EditBlockCoder,
EditBlockFencedCoder,
WholeFileCoder,
PatchCoder,
UnifiedDiffCoder,
# SingleWholeFileFunctionCoder,
ArchitectCoder,
EditorEditBlockCoder,
EditorWholeFileCoder,
EditorDiffFencedCoder,
ContextCoder,
]

View File

@@ -1091,11 +1091,13 @@ class Coder:
if self.suggest_shell_commands:
shell_cmd_prompt = self.gpt_prompts.shell_cmd_prompt.format(platform=platform_text)
shell_cmd_reminder = self.gpt_prompts.shell_cmd_reminder.format(platform=platform_text)
rename_with_shell = self.gpt_prompts.rename_with_shell
else:
shell_cmd_prompt = self.gpt_prompts.no_shell_cmd_prompt.format(platform=platform_text)
shell_cmd_reminder = self.gpt_prompts.no_shell_cmd_reminder.format(
platform=platform_text
)
rename_with_shell = ""
if self.chat_language:
language = self.chat_language
@@ -1115,7 +1117,9 @@ class Coder:
lazy_prompt=lazy_prompt,
platform=platform_text,
shell_cmd_prompt=shell_cmd_prompt,
rename_with_shell=rename_with_shell,
shell_cmd_reminder=shell_cmd_reminder,
go_ahead_tip=self.gpt_prompts.go_ahead_tip,
language=language,
)

View File

@@ -53,3 +53,6 @@ Do not edit these files!
shell_cmd_reminder = ""
no_shell_cmd_prompt = ""
no_shell_cmd_reminder = ""
rename_with_shell = ""
go_ahead_tip = ""

View File

@@ -94,7 +94,8 @@ from hello import hello
),
]
system_reminder = """# *SEARCH/REPLACE block* Rules:
system_reminder = """
# *SEARCH/REPLACE block* Rules:
Every *SEARCH/REPLACE block* must use this format:
1. The opening fence and code language, eg: {fence[0]}python

View File

@@ -181,14 +181,17 @@ If you want to put code in a new file, use a *SEARCH/REPLACE block* with:
- An empty `SEARCH` section
- The new file's contents in the `REPLACE` section
To rename files which have been added to the chat, use shell commands at the end of your response.
{rename_with_shell}{go_ahead_tip}{lazy_prompt}ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!
{shell_cmd_reminder}
"""
If the user just says something like "ok" or "go ahead" or "do that" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.
rename_with_shell = """To rename files which have been added to the chat, use shell commands at the end of your response.
"""
go_ahead_tip = """If the user just says something like "ok" or "go ahead" or "do that" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.
The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.
{lazy_prompt}
ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!
{shell_cmd_reminder}
"""
shell_cmd_reminder = """
@@ -200,4 +203,5 @@ Examples of when to suggest shell commands:
- Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.
- If your code changes add new dependencies, suggest the command to install them.
- Etc.
"""

View File

@@ -0,0 +1,9 @@
from .editblock_fenced_coder import EditBlockFencedCoder
from .editor_diff_fenced_prompts import EditorDiffFencedPrompts
class EditorDiffFencedCoder(EditBlockFencedCoder):
"A coder that uses search/replace blocks, focused purely on editing files."
edit_format = "editor-diff-fenced"
gpt_prompts = EditorDiffFencedPrompts()

View File

@@ -0,0 +1,11 @@
# flake8: noqa: E501
from .editblock_fenced_prompts import EditBlockFencedPrompts
class EditorDiffFencedPrompts(EditBlockFencedPrompts):
shell_cmd_prompt = ""
no_shell_cmd_prompt = ""
shell_cmd_reminder = ""
go_ahead_tip = ""
rename_with_shell = ""

View File

@@ -14,3 +14,5 @@ ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!
shell_cmd_prompt = ""
no_shell_cmd_prompt = ""
shell_cmd_reminder = ""
go_ahead_tip = ""
rename_with_shell = ""

679
aider/coders/patch_coder.py Normal file
View File

@@ -0,0 +1,679 @@
import pathlib
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List, Optional, Tuple
from .base_coder import Coder
from .patch_prompts import PatchPrompts
# --------------------------------------------------------------------------- #
# Domain objects & Exceptions (Adapted from apply_patch.py)
# --------------------------------------------------------------------------- #
class DiffError(ValueError):
"""Any problem detected while parsing or applying a patch."""
class ActionType(str, Enum):
ADD = "Add"
DELETE = "Delete"
UPDATE = "Update"
@dataclass
class Chunk:
orig_index: int = -1 # Line number in the *original* file block where the change starts
del_lines: List[str] = field(default_factory=list)
ins_lines: List[str] = field(default_factory=list)
@dataclass
class PatchAction:
type: ActionType
path: str
# For ADD:
new_content: Optional[str] = None
# For UPDATE:
chunks: List[Chunk] = field(default_factory=list)
move_path: Optional[str] = None
# Type alias for the return type of get_edits
EditResult = Tuple[str, PatchAction]
@dataclass
class Patch:
actions: Dict[str, PatchAction] = field(default_factory=dict)
fuzz: int = 0 # Track fuzziness used during parsing
# --------------------------------------------------------------------------- #
# Helper functions (Adapted from apply_patch.py)
# --------------------------------------------------------------------------- #
def _norm(line: str) -> str:
"""Strip CR so comparisons work for both LF and CRLF input."""
return line.rstrip("\r")
def find_context_core(lines: List[str], context: List[str], start: int) -> Tuple[int, int]:
"""Finds context block, returns start index and fuzz level."""
if not context:
return start, 0
# Exact match
for i in range(start, len(lines) - len(context) + 1):
if lines[i : i + len(context)] == context:
return i, 0
# Rstrip match
norm_context = [s.rstrip() for s in context]
for i in range(start, len(lines) - len(context) + 1):
if [s.rstrip() for s in lines[i : i + len(context)]] == norm_context:
return i, 1 # Fuzz level 1
# Strip match
norm_context_strip = [s.strip() for s in context]
for i in range(start, len(lines) - len(context) + 1):
if [s.strip() for s in lines[i : i + len(context)]] == norm_context_strip:
return i, 100 # Fuzz level 100
return -1, 0
def find_context(lines: List[str], context: List[str], start: int, eof: bool) -> Tuple[int, int]:
"""Finds context, handling EOF marker."""
if eof:
# If EOF marker, first try matching at the very end
if len(lines) >= len(context):
new_index, fuzz = find_context_core(lines, context, len(lines) - len(context))
if new_index != -1:
return new_index, fuzz
# If not found at end, search from `start` as fallback
new_index, fuzz = find_context_core(lines, context, start)
return new_index, fuzz + 10_000 # Add large fuzz penalty if EOF wasn't at end
# Normal case: search from `start`
return find_context_core(lines, context, start)
def peek_next_section(lines: List[str], index: int) -> Tuple[List[str], List[Chunk], int, bool]:
"""
Parses one section (context, -, + lines) of an Update block.
Returns: (context_lines, chunks_in_section, next_index, is_eof)
"""
context_lines: List[str] = []
del_lines: List[str] = []
ins_lines: List[str] = []
chunks: List[Chunk] = []
mode = "keep" # Start by expecting context lines
start_index = index
while index < len(lines):
line = lines[index]
norm_line = _norm(line)
# Check for section terminators
if norm_line.startswith(
(
"@@",
"*** End Patch",
"*** Update File:",
"*** Delete File:",
"*** Add File:",
"*** End of File", # Special terminator
)
):
break
if norm_line == "***": # Legacy/alternative terminator? Handle just in case.
break
if norm_line.startswith("***"): # Invalid line
raise DiffError(f"Invalid patch line found in update section: {line}")
index += 1
last_mode = mode
# Determine line type and strip prefix
if line.startswith("+"):
mode = "add"
line_content = line[1:]
elif line.startswith("-"):
mode = "delete"
line_content = line[1:]
elif line.startswith(" "):
mode = "keep"
line_content = line[1:]
elif line.strip() == "": # Treat blank lines in patch as context ' '
mode = "keep"
line_content = "" # Keep it as a blank line
else:
# Assume lines without prefix are context if format is loose,
# but strict format requires ' '. Raise error for strictness.
raise DiffError(f"Invalid line prefix in update section: {line}")
# If mode changes from add/delete back to keep, finalize the previous chunk
if mode == "keep" and last_mode != "keep":
if del_lines or ins_lines:
chunks.append(
Chunk(
# orig_index is relative to the start of the *context* block found
orig_index=len(context_lines) - len(del_lines),
del_lines=del_lines,
ins_lines=ins_lines,
)
)
del_lines, ins_lines = [], []
# Collect lines based on mode
if mode == "delete":
del_lines.append(line_content)
context_lines.append(line_content) # Deleted lines are part of the original context
elif mode == "add":
ins_lines.append(line_content)
elif mode == "keep":
context_lines.append(line_content)
# Finalize any pending chunk at the end of the section
if del_lines or ins_lines:
chunks.append(
Chunk(
orig_index=len(context_lines) - len(del_lines),
del_lines=del_lines,
ins_lines=ins_lines,
)
)
# Check for EOF marker
is_eof = False
if index < len(lines) and _norm(lines[index]) == "*** End of File":
index += 1
is_eof = True
if index == start_index and not is_eof: # Should not happen if patch is well-formed
raise DiffError("Empty patch section found.")
return context_lines, chunks, index, is_eof
def identify_files_needed(text: str) -> List[str]:
"""Extracts file paths from Update and Delete actions."""
lines = text.splitlines()
paths = set()
for line in lines:
norm_line = _norm(line)
if norm_line.startswith("*** Update File: "):
paths.add(norm_line[len("*** Update File: ") :].strip())
elif norm_line.startswith("*** Delete File: "):
paths.add(norm_line[len("*** Delete File: ") :].strip())
return list(paths)
# --------------------------------------------------------------------------- #
# PatchCoder Class Implementation
# --------------------------------------------------------------------------- #
class PatchCoder(Coder):
"""
A coder that uses a custom patch format for code modifications,
inspired by the format described in tmp.gpt41edits.txt.
Applies patches using logic adapted from the reference apply_patch.py script.
"""
edit_format = "patch"
gpt_prompts = PatchPrompts()
def get_edits(self) -> List[EditResult]:
"""
Parses the LLM response content (containing the patch) into a list of
tuples, where each tuple contains the file path and the PatchAction object.
"""
content = self.partial_response_content
if not content or not content.strip():
return []
# Check for patch sentinels
lines = content.splitlines()
if (
len(lines) < 2
or not _norm(lines[0]).startswith("*** Begin Patch")
# Allow flexible end, might be EOF or just end of stream
# or _norm(lines[-1]) != "*** End Patch"
):
# Tolerate missing sentinels if content looks like a patch action
is_patch_like = any(
_norm(line).startswith(
("@@", "*** Update File:", "*** Add File:", "*** Delete File:")
)
for line in lines
)
if not is_patch_like:
# If it doesn't even look like a patch, return empty
self.io.tool_warning("Response does not appear to be in patch format.")
return []
# If it looks like a patch but lacks sentinels, try parsing anyway but warn.
self.io.tool_warning(
"Patch format warning: Missing '*** Begin Patch'/'*** End Patch' sentinels."
)
start_index = 0
else:
start_index = 1 # Skip "*** Begin Patch"
# Identify files needed for context lookups during parsing
needed_paths = identify_files_needed(content)
current_files: Dict[str, str] = {}
for rel_path in needed_paths:
abs_path = self.abs_root_path(rel_path)
try:
# Use io.read_text to handle potential errors/encodings
file_content = self.io.read_text(abs_path)
if file_content is None:
raise DiffError(
f"File referenced in patch not found or could not be read: {rel_path}"
)
current_files[rel_path] = file_content
except FileNotFoundError:
raise DiffError(f"File referenced in patch not found: {rel_path}")
except IOError as e:
raise DiffError(f"Error reading file {rel_path}: {e}")
try:
# Parse the patch text using adapted logic
patch_obj = self._parse_patch_text(lines, start_index, current_files)
# Convert Patch object actions dict to a list of tuples (path, action)
# for compatibility with the base Coder's prepare_to_edit method.
results = []
for path, action in patch_obj.actions.items():
results.append((path, action))
return results
except DiffError as e:
# Raise as ValueError for consistency with other coders' error handling
raise ValueError(f"Error parsing patch content: {e}")
except Exception as e:
# Catch unexpected errors during parsing
raise ValueError(f"Unexpected error parsing patch: {e}")
def _parse_patch_text(
self, lines: List[str], start_index: int, current_files: Dict[str, str]
) -> Patch:
"""
Parses patch content lines into a Patch object.
Adapted from the Parser class in apply_patch.py.
"""
patch = Patch()
index = start_index
fuzz_accumulator = 0
while index < len(lines):
line = lines[index]
norm_line = _norm(line)
if norm_line == "*** End Patch":
index += 1
break # Successfully reached end
# ---------- UPDATE ---------- #
if norm_line.startswith("*** Update File: "):
path = norm_line[len("*** Update File: ") :].strip()
index += 1
if not path:
raise DiffError("Update File action missing path.")
if path in patch.actions:
raise DiffError(f"Duplicate action for file: {path}")
if path not in current_files:
raise DiffError(f"Update File Error - missing file content for: {path}")
move_to = None
if index < len(lines) and _norm(lines[index]).startswith("*** Move to: "):
move_to = _norm(lines[index])[len("*** Move to: ") :].strip()
index += 1
if not move_to:
raise DiffError("Move to action missing path.")
file_content = current_files[path]
action, index, fuzz = self._parse_update_file_sections(lines, index, file_content)
action.path = path # Ensure path is set
action.move_path = move_to
patch.actions[path] = action
fuzz_accumulator += fuzz
continue
# ---------- DELETE ---------- #
elif norm_line.startswith("*** Delete File: "):
path = norm_line[len("*** Delete File: ") :].strip()
index += 1
if not path:
raise DiffError("Delete File action missing path.")
if path in patch.actions:
raise DiffError(f"Duplicate action for file: {path}")
if path not in current_files:
raise DiffError(
f"Delete File Error - file not found: {path}"
) # Check against known files
patch.actions[path] = PatchAction(type=ActionType.DELETE, path=path)
continue
# ---------- ADD ---------- #
elif norm_line.startswith("*** Add File: "):
path = norm_line[len("*** Add File: ") :].strip()
index += 1
if not path:
raise DiffError("Add File action missing path.")
if path in patch.actions:
raise DiffError(f"Duplicate action for file: {path}")
# Check if file exists in the context provided (should not for Add).
# Note: We only have needed files, a full check requires FS access.
# if path in current_files:
# raise DiffError(f"Add File Error - file already exists: {path}")
action, index = self._parse_add_file_content(lines, index)
action.path = path # Ensure path is set
patch.actions[path] = action
continue
# If we are here, the line is unexpected
# Allow blank lines between actions
if not norm_line.strip():
index += 1
continue
raise DiffError(f"Unknown or misplaced line while parsing patch: {line}")
# Check if we consumed the whole input or stopped early
# Tolerate missing "*** End Patch" if we processed actions
# if index < len(lines) and _norm(lines[index-1]) != "*** End Patch":
# raise DiffError("Patch parsing finished unexpectedly before end of input.")
patch.fuzz = fuzz_accumulator
return patch
def _parse_update_file_sections(
self, lines: List[str], index: int, file_content: str
) -> Tuple[PatchAction, int, int]:
"""Parses all sections (@@, context, -, +) for a single Update File action."""
action = PatchAction(type=ActionType.UPDATE, path="") # Path set by caller
orig_lines = file_content.splitlines() # Use splitlines for consistency
current_file_index = 0 # Track position in original file content
total_fuzz = 0
while index < len(lines):
norm_line = _norm(lines[index])
# Check for terminators for *this* file update
if norm_line.startswith(
(
"*** End Patch",
"*** Update File:",
"*** Delete File:",
"*** Add File:",
)
):
break # End of this file's update section
# Handle @@ scope lines (optional)
scope_lines = []
while index < len(lines) and _norm(lines[index]).startswith("@@"):
scope_line_content = lines[index][len("@@") :].strip()
if scope_line_content: # Ignore empty @@ lines?
scope_lines.append(scope_line_content)
index += 1
# Find the scope in the original file if specified
if scope_lines:
# Simple scope finding: search from current position
# A more robust finder could handle nested scopes like the reference @@ @@
found_scope = False
temp_index = current_file_index
while temp_index < len(orig_lines):
# Check if all scope lines match sequentially from temp_index
match = True
for i, scope in enumerate(scope_lines):
if (
temp_index + i >= len(orig_lines)
or _norm(orig_lines[temp_index + i]).strip() != scope
):
match = False
break
if match:
current_file_index = temp_index + len(scope_lines)
found_scope = True
break
temp_index += 1
if not found_scope:
# Try fuzzy scope matching (strip whitespace)
temp_index = current_file_index
while temp_index < len(orig_lines):
match = True
for i, scope in enumerate(scope_lines):
if (
temp_index + i >= len(orig_lines)
or _norm(orig_lines[temp_index + i]).strip() != scope.strip()
):
match = False
break
if match:
current_file_index = temp_index + len(scope_lines)
found_scope = True
total_fuzz += 1 # Add fuzz for scope match difference
break
temp_index += 1
if not found_scope:
scope_txt = "\n".join(scope_lines)
raise DiffError(f"Could not find scope context:\n{scope_txt}")
# Peek and parse the next context/change section
context_block, chunks_in_section, next_index, is_eof = peek_next_section(lines, index)
# Find where this context block appears in the original file
found_index, fuzz = find_context(orig_lines, context_block, current_file_index, is_eof)
total_fuzz += fuzz
if found_index == -1:
ctx_txt = "\n".join(context_block)
marker = "*** End of File" if is_eof else ""
raise DiffError(
f"Could not find patch context {marker} starting near line"
f" {current_file_index}:\n{ctx_txt}"
)
# Adjust chunk original indices to be absolute within the file
for chunk in chunks_in_section:
# chunk.orig_index from peek is relative to context_block start
# We need it relative to the file start
chunk.orig_index += found_index
action.chunks.append(chunk)
# Advance file index past the matched context block
current_file_index = found_index + len(context_block)
# Advance line index past the processed section in the patch
index = next_index
return action, index, total_fuzz
def _parse_add_file_content(self, lines: List[str], index: int) -> Tuple[PatchAction, int]:
"""Parses the content (+) lines for an Add File action."""
added_lines: List[str] = []
while index < len(lines):
line = lines[index]
norm_line = _norm(line)
# Stop if we hit another action or end marker
if norm_line.startswith(
(
"*** End Patch",
"*** Update File:",
"*** Delete File:",
"*** Add File:",
)
):
break
# Expect lines to start with '+'
if not line.startswith("+"):
# Tolerate blank lines? Or require '+'? Reference implies '+' required.
if norm_line.strip() == "":
# Treat blank line as adding a blank line
added_lines.append("")
else:
raise DiffError(f"Invalid Add File line (missing '+'): {line}")
else:
added_lines.append(line[1:]) # Strip leading '+'
index += 1
action = PatchAction(type=ActionType.ADD, path="", new_content="\n".join(added_lines))
return action, index
def apply_edits(self, edits: List[PatchAction]):
"""
Applies the parsed PatchActions to the corresponding files.
"""
if not edits:
return
# Group edits by original path? Not strictly needed if processed sequentially.
# Edits are now List[Tuple[str, PatchAction]]
for _path_tuple_element, action in edits:
# action is the PatchAction object
# action.path is the canonical path within the action logic
full_path = self.abs_root_path(action.path)
path_obj = pathlib.Path(full_path)
try:
if action.type == ActionType.ADD:
# Check existence *before* writing
if path_obj.exists():
raise DiffError(f"ADD Error: File already exists: {action.path}")
if action.new_content is None:
# Parser should ensure this doesn't happen
raise DiffError(f"ADD change for {action.path} has no content")
self.io.tool_output(f"Adding {action.path}")
path_obj.parent.mkdir(parents=True, exist_ok=True)
# Ensure single trailing newline, matching reference behavior
content_to_write = action.new_content
if not content_to_write.endswith("\n"):
content_to_write += "\n"
self.io.write_text(full_path, content_to_write)
elif action.type == ActionType.DELETE:
self.io.tool_output(f"Deleting {action.path}")
if not path_obj.exists():
self.io.tool_warning(
f"DELETE Warning: File not found, skipping: {action.path}"
)
else:
path_obj.unlink()
elif action.type == ActionType.UPDATE:
if not path_obj.exists():
raise DiffError(f"UPDATE Error: File does not exist: {action.path}")
current_content = self.io.read_text(full_path)
if current_content is None:
# Should have been caught during parsing if file was needed
raise DiffError(f"Could not read file for UPDATE: {action.path}")
# Apply the update logic using the parsed chunks
new_content = self._apply_update(current_content, action, action.path)
target_full_path = (
self.abs_root_path(action.move_path) if action.move_path else full_path
)
target_path_obj = pathlib.Path(target_full_path)
if action.move_path:
self.io.tool_output(
f"Updating and moving {action.path} to {action.move_path}"
)
# Check if target exists before overwriting/moving
if target_path_obj.exists() and full_path != target_full_path:
self.io.tool_warning(
"UPDATE Warning: Target file for move already exists, overwriting:"
f" {action.move_path}"
)
else:
self.io.tool_output(f"Updating {action.path}")
# Ensure parent directory exists for target
target_path_obj.parent.mkdir(parents=True, exist_ok=True)
self.io.write_text(target_full_path, new_content)
# Remove original file *after* successful write to new location if moved
if action.move_path and full_path != target_full_path:
path_obj.unlink()
else:
# Should not happen
raise DiffError(f"Unknown action type encountered: {action.type}")
except (DiffError, FileNotFoundError, IOError, OSError) as e:
# Raise a ValueError to signal failure, consistent with other coders.
raise ValueError(f"Error applying action '{action.type}' to {action.path}: {e}")
except Exception as e:
# Catch unexpected errors during application
raise ValueError(
f"Unexpected error applying action '{action.type}' to {action.path}: {e}"
)
def _apply_update(self, text: str, action: PatchAction, path: str) -> str:
"""
Applies UPDATE chunks to the given text content.
Adapted from _get_updated_file in apply_patch.py.
"""
if action.type is not ActionType.UPDATE:
# Should not be called otherwise, but check for safety
raise DiffError("_apply_update called with non-update action")
orig_lines = text.splitlines() # Use splitlines to handle endings consistently
dest_lines: List[str] = []
current_orig_line_idx = 0 # Tracks index in orig_lines processed so far
# Sort chunks by their original index to apply them sequentially
sorted_chunks = sorted(action.chunks, key=lambda c: c.orig_index)
for chunk in sorted_chunks:
# chunk.orig_index is the absolute line number where the change starts
# (where the first deleted line was, or where inserted lines go if no deletes)
chunk_start_index = chunk.orig_index
if chunk_start_index < current_orig_line_idx:
# This indicates overlapping chunks or incorrect indices from parsing
raise DiffError(
f"{path}: Overlapping or out-of-order chunk detected."
f" Current index {current_orig_line_idx}, chunk starts at {chunk_start_index}."
)
# Add lines from original file between the last chunk and this one
dest_lines.extend(orig_lines[current_orig_line_idx:chunk_start_index])
# Verify that the lines to be deleted actually match the original file content
# (The parser should have used find_context, but double-check here)
num_del = len(chunk.del_lines)
actual_deleted_lines = orig_lines[chunk_start_index : chunk_start_index + num_del]
# Use the same normalization as find_context_core for comparison robustness
norm_chunk_del = [_norm(s).strip() for s in chunk.del_lines]
norm_actual_del = [_norm(s).strip() for s in actual_deleted_lines]
if norm_chunk_del != norm_actual_del:
# This indicates the context matching failed or the file changed since parsing
# Provide detailed error message
expected_str = "\n".join(f"- {s}" for s in chunk.del_lines)
actual_str = "\n".join(f" {s}" for s in actual_deleted_lines)
raise DiffError(
f"{path}: Mismatch applying patch near line {chunk_start_index + 1}.\n"
f"Expected lines to remove:\n{expected_str}\n"
f"Found lines in file:\n{actual_str}"
)
# Add the inserted lines from the chunk
dest_lines.extend(chunk.ins_lines)
# Advance the original line index past the lines processed (deleted lines)
current_orig_line_idx = chunk_start_index + num_del
# Add any remaining lines from the original file after the last chunk
dest_lines.extend(orig_lines[current_orig_line_idx:])
# Join lines and ensure a single trailing newline
result = "\n".join(dest_lines)
if result or orig_lines: # Add newline unless result is empty and original was empty
result += "\n"
return result

View File

@@ -0,0 +1,145 @@
# flake8: noqa: E501
from .base_prompts import CoderPrompts
from .editblock_prompts import EditBlockPrompts
class PatchPrompts(EditBlockPrompts):
main_system = """Act as an expert software developer.
Always use best practices when coding.
Respect and use existing conventions, libraries, etc that are already present in the code base.
{lazy_prompt}
Take requests for changes to the supplied code.
If the request is ambiguous, ask questions.
Always reply to the user in {language}.
Once you understand the request you MUST:
1. Decide if you need to propose edits to any files that haven't been added to the chat. You can create new files without asking!
But if you need to propose edits to existing files not already added to the chat, you *MUST* tell the user their full path names and ask them to *add the files to the chat*.
End your reply and wait for their approval.
You can keep asking if you then decide you need to edit more files.
2. Think step-by-step and explain the needed changes in a few short sentences.
3. Describe the changes using the V4A diff format, enclosed within `*** Begin Patch` and `*** End Patch` markers.
All changes to files must use the V4A diff format specified in the examples and reminder section.
ONLY EVER RETURN CODE IN THE SPECIFIED V4A DIFF FORMAT!
{shell_cmd_prompt}
"""
example_messages = [
dict(
role="user",
content="Change get_factorial() to use math.factorial",
),
dict(
role="assistant",
content="""To make this change we need to modify `mathweb/flask/app.py` to:
1. Import the math package.
2. Remove the existing factorial() function.
3. Update get_factorial() to call math.factorial instead.
Here is the patch:
*** Begin Patch
*** Update File: mathweb/flask/app.py
@@ class MathWeb:
from flask import Flask
import math
from flask import Flask
*** Update File: mathweb/flask/app.py
@@ def get_factorial(self, n):
-def factorial(n):
- "compute factorial"
-
- if n == 0:
- return 1
- else:
- return n * factorial(n-1)
-
*** Update File: mathweb/flask/app.py
@@ def get_factorial(self, n):
- return str(factorial(n))
+ return str(math.factorial(n))
*** End Patch
""",
),
dict(
role="user",
content="Refactor hello() into its own file.",
),
dict(
role="assistant",
content="""To make this change we need to modify `main.py` and make a new file `hello.py`:
1. Make a new hello.py file with hello() in it.
2. Remove hello() from main.py and replace it with an import.
Here is the patch:
*** Begin Patch
*** Add File: hello.py
+# A simple function
+def hello():
+ "print a greeting"
+
+ print("hello")
*** Update File: main.py
@@ def main():
-def hello():
- "print a greeting"
-
- print("hello")
+from hello import hello
*** End Patch
""",
),
]
system_reminder = """# V4A Diff Format Rules:
Your entire response containing the patch MUST start with `*** Begin Patch` on a line by itself.
Your entire response containing the patch MUST end with `*** End Patch` on a line by itself.
Use the *FULL* file path, as shown to you by the user.
{quad_backtick_reminder}
For each file you need to modify, start with a marker line:
`*** [ACTION] File: [path/to/file]`
Where `[ACTION]` is one of `Add`, `Update`, or `Delete`.
Use the *FULL* file path, as shown to you by the user.
For `Update` actions, describe each snippet of code that needs to be changed using the following format:
1. Context lines: Include 3 lines of context *before* the change. These lines MUST start with a single space ` `.
2. Lines to remove: Precede each line to be removed with a minus sign `-`.
3. Lines to add: Precede each line to be added with a plus sign `+`.
4. Context lines: Include 3 lines of context *after* the change. These lines MUST start with a single space ` `.
Context lines MUST exactly match the existing file content, character for character, including indentation.
If a change is near the beginning or end of the file, include fewer than 3 context lines as appropriate.
If 3 lines of context is insufficient to uniquely identify the snippet, use `@@ [CLASS_OR_FUNCTION_NAME]` markers on their own lines *before* the context lines to specify the scope. You can use multiple `@@` markers if needed.
Do not include line numbers.
Only create patches for files that the user has added to the chat!
To move code within a file, use two `*** Update File:` sections: one to delete the code (using `-` lines) from its original location, and another to add the code (using `+` lines) in the new location.
Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.
For `Add` actions, use the `*** Add File: [path/to/new/file]` marker, followed by the lines of the new file, each preceded by a plus sign `+`.
For `Delete` actions, use the `*** Delete File: [path/to/file]` marker. No other lines are needed for the deletion.
{rename_with_shell}{go_ahead_tip}{lazy_prompt}ONLY EVER RETURN CODE IN THE SPECIFIED V4A DIFF FORMAT!
{shell_cmd_reminder}
"""

View File

@@ -235,20 +235,6 @@ Left
Left
"""
"""
ri = RelativeIndenter([example])
dump(example)
rel_example = ri.make_relative(example)
dump(repr(rel_example))
abs_example = ri.make_absolute(rel_example)
dump(abs_example)
sys.exit()
"""
def relative_indent(texts):
ri = RelativeIndenter(texts)
@@ -349,7 +335,7 @@ def lines_to_chars(lines, mapping):
return new_text
def dmp_lines_apply(texts, remap=True):
def dmp_lines_apply(texts):
debug = False
# debug = True
@@ -655,8 +641,6 @@ def proc(dname):
(dmp_lines_apply, all_preprocs),
]
_strategies = editblock_strategies # noqa: F841
short_names = dict(
search_and_replace="sr",
git_cherry_pick_osr_onto_o="cp_o",

View File

@@ -45,6 +45,7 @@ other_hunks_applied = (
class UnifiedDiffCoder(Coder):
"""A coder that uses unified diff format for code modifications."""
edit_format = "udiff"
gpt_prompts = UnifiedDiffPrompts()
@@ -344,7 +345,16 @@ def process_fenced_block(lines, start_line_num):
if block[0].startswith("--- ") and block[1].startswith("+++ "):
# Extract the file path, considering that it might contain spaces
fname = block[1][4:].strip()
a_fname = block[0][4:].strip()
b_fname = block[1][4:].strip()
# Check if standard git diff prefixes are present and strip them
if a_fname.startswith("a/") and b_fname.startswith("b/"):
fname = b_fname[2:]
else:
# Otherwise, assume the path is as intended
fname = b_fname
block = block[2:]
else:
fname = None

View File

@@ -857,7 +857,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
)
if args.copy_paste and args.edit_format is None:
if main_model.edit_format in ("diff", "whole"):
if main_model.edit_format in ("diff", "whole", "diff-fenced"):
main_model.edit_format = "editor-" + main_model.edit_format
if args.verbose:

View File

@@ -314,7 +314,11 @@ class Model(ModelSettings):
self.apply_generic_model_settings(model)
# Apply override settings last if they exist
if self.extra_model_settings and self.extra_model_settings.extra_params:
if (
self.extra_model_settings
and self.extra_model_settings.extra_params
and self.extra_model_settings.name == "aider/extra_params"
):
# Initialize extra_params if it doesn't exist
if not self.extra_params:
self.extra_params = {}
@@ -334,10 +338,25 @@ class Model(ModelSettings):
self.use_repo_map = True
self.use_temperature = False
self.system_prompt_prefix = "Formatting re-enabled. "
self.system_prompt_prefix = "Formatting re-enabled. "
if "reasoning_effort" not in self.accepts_settings:
self.accepts_settings.append("reasoning_effort")
return # <--
if "gpt-4.1-mini" in model:
self.edit_format = "diff"
self.use_repo_map = True
self.reminder = "sys"
self.examples_as_sys_msg = False
return # <--
if "gpt-4.1" in model:
self.edit_format = "diff"
self.use_repo_map = True
self.reminder = "sys"
self.examples_as_sys_msg = False
return # <--
if "/o1-mini" in model:
self.use_repo_map = True
self.use_temperature = False
@@ -488,6 +507,8 @@ class Model(ModelSettings):
if not self.editor_edit_format:
self.editor_edit_format = self.editor_model.edit_format
if self.editor_edit_format in ("diff", "whole", "diff-fenced"):
self.editor_edit_format = "editor-" + self.editor_edit_format
return self.editor_model

View File

@@ -550,6 +550,42 @@
"litellm_provider": "xai",
"mode": "chat"
},
"openrouter/x-ai/grok-3-fast-beta": {
"max_tokens": 131072,
"max_input_tokens": 131072,
"max_output_tokens": 131072,
"input_cost_per_token": 0.000005,
"output_cost_per_token": 0.000025,
"litellm_provider": "openrouter",
"mode": "chat"
},
"xai/grok-3-fast-beta": {
"max_tokens": 131072,
"max_input_tokens": 131072,
"max_output_tokens": 131072,
"input_cost_per_token": 0.000005,
"output_cost_per_token": 0.000025,
"litellm_provider": "xai",
"mode": "chat"
},
"openrouter/x-ai/grok-3-mini-fast-beta": {
"max_tokens": 131072,
"max_input_tokens": 131072,
"max_output_tokens": 131072,
"input_cost_per_token": 0.0000006,
"output_cost_per_token": 0.000004,
"litellm_provider": "openrouter",
"mode": "chat"
},
"xai/grok-3-mini-fast-beta": {
"max_tokens": 131072,
"max_input_tokens": 131072,
"max_output_tokens": 131072,
"input_cost_per_token": 0.0000006,
"output_cost_per_token": 0.000004,
"litellm_provider": "xai",
"mode": "chat"
},
"openrouter/google/gemini-2.0-flash-exp:free": {
"max_tokens": 8192,
"max_input_tokens": 1048576,

View File

@@ -1006,17 +1006,364 @@
# extra_body:
# reasoning_effort: high
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: xai/grok-3-mini-beta
use_repo_map: true
edit_format: whole
accepts_settings:
- reasoning_effort
- reasoning_effort
#extra_params:
# extra_body:
# reasoning_effort: low
- name: openrouter/x-ai/grok-3-fast-beta
use_repo_map: true
edit_format: diff
- name: xai/grok-3-fast-beta
use_repo_map: true
edit_format: diff
- name: openrouter/x-ai/grok-3-mini-fast-beta
use_repo_map: true
edit_format: whole
accepts_settings:
- reasoning_effort
- name: xai/grok-3-mini-fast-beta
use_repo_map: true
edit_format: whole
accepts_settings:
- reasoning_effort
- name: openrouter/openrouter/optimus-alpha
use_repo_map: true
edit_format: diff
examples_as_sys_msg: true
- name: gpt-4.1
edit_format: diff
weak_model_name: gpt-4.1-mini
use_repo_map: true
reminder: sys # user: 52.x%/96.9%
examples_as_sys_msg: false # true: 51.6% correct, 95.6% well formed; false: 52.4%/98.2%
editor_model_name: gpt-4.1-mini
- name: openai/gpt-4.1
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
reminder: sys
examples_as_sys_msg: false
editor_model_name: openai/gpt-4.1-mini
- name: azure/gpt-4.1
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
reminder: sys
examples_as_sys_msg: false
editor_model_name: azure/gpt-4.1-mini
- name: openrouter/openai/gpt-4.1
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
reminder: sys
examples_as_sys_msg: false
editor_model_name: openrouter/openai/gpt-4.1-mini
- name: gpt-4.1-mini
edit_format: diff
use_repo_map: true
reminder: sys
examples_as_sys_msg: false # false: 32.x%/92.4% (60+ malformed responses); true: 31.7/90.2/60+
- name: openai/gpt-4.1-mini
edit_format: diff
use_repo_map: true
reminder: sys
examples_as_sys_msg: false
- name: azure/gpt-4.1-mini
edit_format: diff
use_repo_map: true
reminder: sys
examples_as_sys_msg: false
- name: openrouter/openai/gpt-4.1-mini
edit_format: diff
use_repo_map: true
reminder: sys
examples_as_sys_msg: false
- name: o3
streaming: false
edit_format: diff
weak_model_name: gpt-4.1-mini
use_repo_map: true
editor_model_name: gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openai/o3
streaming: false
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openrouter/openai/o3
streaming: false
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: azure/o3
streaming: false
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
- name: o4-mini
edit_format: diff
weak_model_name: gpt-4.1-mini
use_repo_map: true
use_temperature: false
editor_model_name: gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: "Formatting re-enabled. "
accepts_settings: ["reasoning_effort"]
examples_as_sys_msg: true
#extra_params:
# extra_body:
# reasoning_effort: high

View File

@@ -24,11 +24,20 @@ cog.out(text)
]]]-->
### main branch
### Aider v0.82.0
- Support for GPT 4.1, mini and nano.
- Added new `patch` edit format for OpenAI's GPT-4.1 model.
- Improved support for using architect mode with Gemini 2.5 Pro.
- Added new `editor-diff`, `editor-whole`, and `editor-diff-fenced` edit formats.
- Bugfix for automatically selecting the best edit format to use in architect mode.
- Added support for `grok-3-fast-beta` and `grok-3-mini-fast-beta` models.
- Aider wrote 92% of the code in this release.
### Aider v0.81.3
- Commit messages generated by aider are no longer forced to be entirely lowercase, by Peter Hadlaw.
- Updated default settings for Grok models.
- Aider wrote 64% of the code in this release.
### Aider v0.81.2
@@ -40,14 +49,12 @@ cog.out(text)
- Fix quoting of values containing '#' in the sample `aider.conf.yml`.
- Add support for Fireworks AI model 'deepseek-v3-0324', by Felix Lisczyk.
- Commit messages generated by aider are now lowercase, by Anton Ödman.
- Aider wrote 64% of the code in this release.
### Aider v0.81.1
- Added support for the `gemini/gemini-2.5-pro-preview-03-25` model.
- Updated the `gemini` alias to point to `gemini/gemini-2.5-pro-preview-03-25`.
- Added the `gemini-exp` alias for `gemini/gemini-2.5-pro-exp-03-25`.
- Aider wrote 87% of the code in this release.
### Aider v0.81.0

View File

@@ -4448,3 +4448,55 @@
Paul Gauthier (aider): 225
start_tag: v0.80.0
total_lines: 263
- aider_percentage: 91.85
aider_total: 1567
end_date: '2025-04-14'
end_tag: v0.82.0
file_counts:
aider/__init__.py:
Paul Gauthier: 1
aider/args_formatter.py:
Paul Gauthier (aider): 4
aider/coders/__init__.py:
Paul Gauthier (aider): 4
aider/coders/base_coder.py:
Paul Gauthier: 4
Paul Gauthier (aider): 5
aider/coders/editor_diff_fenced_coder.py:
Paul Gauthier (aider): 9
aider/coders/patch_coder.py:
Paul Gauthier (aider): 679
aider/coders/search_replace.py:
Paul Gauthier (aider): 1
aider/main.py:
Paul Gauthier (aider): 1
aider/models.py:
Paul Gauthier: 1
Paul Gauthier (aider): 25
aider/resources/model-settings.yml:
Felix Lisczyk: 13
Paul Gauthier: 37
Paul Gauthier (aider): 68
aider/website/_includes/leaderboard.js:
Paul Gauthier: 38
Paul Gauthier (aider): 6
aider/website/_includes/leaderboard_table.js:
Paul Gauthier (aider): 518
aider/website/docs/leaderboards/index.md:
Paul Gauthier: 15
Paul Gauthier (aider): 209
aider/website/index.html:
Paul Gauthier: 28
scripts/homepage.py:
Paul Gauthier (aider): 2
scripts/versionbump.py:
Paul Gauthier (aider): 11
tests/basic/test_coder.py:
Paul Gauthier: 2
Paul Gauthier (aider): 25
grand_total:
Felix Lisczyk: 13
Paul Gauthier: 126
Paul Gauthier (aider): 1567
start_tag: v0.81.0
total_lines: 1706

View File

@@ -643,7 +643,7 @@
exhausted_context_windows: 0
test_timeouts: 1
total_tests: 225
command: "aider --model anthropic/claude-3-7-sonnet-20250219 # plus yml config"
command: "aider --model anthropic/claude-3-7-sonnet-20250219 --thinking-tokens 32k"
date: 2025-02-24
versions: 0.75.1.dev
seconds_per_case: 105.2
@@ -1013,4 +1013,134 @@
date: 2025-04-10
versions: 0.81.2.dev
seconds_per_case: 18.4
total_cost: 0.0000
total_cost: 0.0000
- dirname: 2025-04-14-21-05-54--gpt41-diff-exuser
test_cases: 225
model: gpt-4.1
edit_format: diff
commit_hash: 7a87db5-dirty
pass_rate_1: 20.0
pass_rate_2: 52.4
pass_num_1: 45
pass_num_2: 118
percent_cases_well_formed: 98.2
error_outputs: 6
num_malformed_responses: 5
num_with_malformed_responses: 4
user_asks: 171
lazy_comments: 0
syntax_errors: 0
indentation_errors: 0
exhausted_context_windows: 1
test_timeouts: 5
total_tests: 225
command: aider --model gpt-4.1
date: 2025-04-14
versions: 0.81.4.dev
seconds_per_case: 20.5
total_cost: 9.8556
- dirname: 2025-04-14-21-27-53--gpt41mini-diff
test_cases: 225
model: gpt-4.1-mini
edit_format: diff
commit_hash: ffb743e-dirty
pass_rate_1: 11.1
pass_rate_2: 32.4
pass_num_1: 25
pass_num_2: 73
percent_cases_well_formed: 92.4
error_outputs: 64
num_malformed_responses: 62
num_with_malformed_responses: 17
user_asks: 159
lazy_comments: 0
syntax_errors: 0
indentation_errors: 0
exhausted_context_windows: 2
test_timeouts: 2
total_tests: 225
command: aider --model gpt-4.1-mini
date: 2025-04-14
versions: 0.81.4.dev
seconds_per_case: 19.5
total_cost: 1.9918
- dirname: 2025-04-14-22-46-01--gpt41nano-diff
test_cases: 225
model: gpt-4.1-nano
edit_format: whole
commit_hash: 71d1591-dirty
pass_rate_1: 3.1
pass_rate_2: 8.9
pass_num_1: 7
pass_num_2: 20
percent_cases_well_formed: 94.2
error_outputs: 20
num_malformed_responses: 20
num_with_malformed_responses: 13
user_asks: 316
lazy_comments: 0
syntax_errors: 0
indentation_errors: 0
exhausted_context_windows: 0
test_timeouts: 8
total_tests: 225
command: aider --model gpt-4.1-nano
date: 2025-04-14
versions: 0.81.4.dev
seconds_per_case: 12.0
total_cost: 0.4281
- dirname: 2025-04-16-21-20-55--o3-high-diff-temp0-exsys
test_cases: 225
model: o3 (high)
edit_format: diff
commit_hash: 24805ff-dirty
pass_rate_1: 36.9
pass_rate_2: 79.6
pass_num_1: 83
pass_num_2: 179
percent_cases_well_formed: 95.1
error_outputs: 11
num_malformed_responses: 11
num_with_malformed_responses: 11
user_asks: 110
lazy_comments: 0
syntax_errors: 0
indentation_errors: 0
exhausted_context_windows: 0
test_timeouts: 2
total_tests: 225
command: aider --model o3
date: 2025-04-16
versions: 0.82.1.dev
seconds_per_case: 113.8
total_cost: 111.0325
- dirname: 2025-04-16-22-01-58--o4-mini-high-diff-exsys
test_cases: 225
model: o4-mini (high)
edit_format: diff
commit_hash: b66901f-dirty
pass_rate_1: 19.6
pass_rate_2: 72.0
pass_num_1: 44
pass_num_2: 162
percent_cases_well_formed: 90.7
error_outputs: 26
num_malformed_responses: 24
num_with_malformed_responses: 21
user_asks: 66
lazy_comments: 0
syntax_errors: 0
indentation_errors: 0
exhausted_context_windows: 1
test_timeouts: 2
total_tests: 225
command: aider --model o4-mini
date: 2025-04-16
versions: 0.82.1.dev
seconds_per_case: 176.5
total_cost: 19.6399

View File

@@ -0,0 +1,514 @@
document.addEventListener('DOMContentLoaded', function() {
let currentMode = 'view'; // 'view', 'select', 'detail'
let selectedRows = new Set(); // Store indices of selected rows
const allMainRows = document.querySelectorAll('tr[id^="main-row-"]');
const allDetailsRows = document.querySelectorAll('tr[id^="details-"]');
const searchInput = document.getElementById('editSearchInput');
const modeViewButton = document.getElementById('mode-view-btn');
const modeDetailButton = document.getElementById('mode-detail-btn');
const modeSelectButton = document.getElementById('mode-select-btn');
const modeButtons = [modeViewButton, modeSelectButton, modeDetailButton];
const selectAllCheckbox = document.getElementById('select-all-checkbox');
const leaderboardTitle = document.getElementById('leaderboard-title'); // Get title element
const defaultTitle = "Aider polyglot coding leaderboard";
const filteredTitle = "Aider polyglot coding benchmark results";
function applySearchFilter() {
const searchTerm = searchInput.value.toLowerCase();
allMainRows.forEach(row => {
const textContent = row.textContent.toLowerCase();
const detailsRow = document.getElementById(row.id.replace('main-row-', 'details-'));
const matchesSearch = textContent.includes(searchTerm);
if (matchesSearch) {
row.classList.remove('hidden-by-search');
if (detailsRow) detailsRow.classList.remove('hidden-by-search');
} else {
row.classList.add('hidden-by-search');
if (detailsRow) detailsRow.classList.add('hidden-by-search');
}
});
// After applying search filter, re-apply view mode filter and update select-all state
updateTableView(currentMode);
if (currentMode === 'select') {
updateSelectAllCheckboxState();
}
// Update cost bars and ticks since visible rows may have changed
updateCostBars();
updateCostTicks();
}
function getVisibleMainRows() {
// Helper to get rows currently visible (not hidden by search or mode)
return Array.from(allMainRows).filter(row =>
!row.classList.contains('hidden-by-search') && !row.classList.contains('hidden-by-mode')
);
}
function updateSelectAllCheckboxState() {
// Update the header checkbox based on the selection state of *visible* rows
if (currentMode !== 'select') return; // Only relevant in select mode
const visibleRows = getVisibleMainRows();
const visibleRowCount = visibleRows.length;
const selectedVisibleRowCount = visibleRows.filter(row => selectedRows.has(row.querySelector('.row-selector')?.dataset.rowIndex)).length;
if (visibleRowCount === 0) {
selectAllCheckbox.checked = false;
selectAllCheckbox.indeterminate = false;
} else if (selectedVisibleRowCount === visibleRowCount) {
selectAllCheckbox.checked = true;
selectAllCheckbox.indeterminate = false;
} else if (selectedVisibleRowCount > 0) {
selectAllCheckbox.checked = false;
selectAllCheckbox.indeterminate = true;
} else {
selectAllCheckbox.checked = false;
selectAllCheckbox.indeterminate = false;
}
}
function updateTableView(mode) {
currentMode = mode; // Update global state ('view', 'select', 'detail')
// Update button styles first
modeButtons.forEach(btn => {
btn.classList.remove('active');
// Reset specific styles potentially added by .active
btn.style.backgroundColor = '';
btn.style.color = '';
});
let activeButton;
if (mode === 'view') activeButton = modeViewButton;
else if (mode === 'select') activeButton = modeSelectButton;
else if (mode === 'detail') activeButton = modeDetailButton;
activeButton.classList.add('active');
activeButton.style.backgroundColor = '#e7f3ff'; // Use selected row highlight blue
activeButton.style.color = '#495057'; // Use dark text for contrast on light blue
// Get the first header cell (for the toggle/checkbox column)
const firstHeaderCell = document.querySelector('table thead th:first-child');
// Show/hide header checkbox based on mode
selectAllCheckbox.style.display = mode === 'select' ? 'inline-block' : 'none';
allMainRows.forEach(row => {
const rowIndex = row.querySelector('.row-selector')?.dataset.rowIndex;
const toggleButton = row.querySelector('.toggle-details');
const selectorCheckbox = row.querySelector('.row-selector');
const firstCell = row.querySelector('td:first-child'); // Get the first cell of the main row
const detailsRow = document.getElementById(`details-${rowIndex}`);
const isSelected = selectedRows.has(rowIndex);
// Reset visibility classes before applying mode logic
row.classList.remove('hidden-by-mode');
if (detailsRow) detailsRow.classList.remove('hidden-by-mode');
// Show/hide the first column (header and data cells) based on mode
if (firstHeaderCell) {
firstHeaderCell.style.display = mode === 'view' ? 'none' : '';
}
if (firstCell) {
firstCell.style.display = mode === 'view' ? 'none' : '';
}
// Apply mode-specific logic
if (mode === 'view') { // --- VIEW MODE ---
toggleButton.style.display = 'none'; // Hide toggle in view mode
selectorCheckbox.style.display = 'none';
row.classList.remove('row-selected'); // Ensure no selection highlight
// view-highlighted is handled by row click listener
// In 'view' mode, hide row if selections exist AND this row is NOT selected
if (selectedRows.size > 0 && !isSelected) {
row.classList.add('hidden-by-mode');
if (detailsRow) detailsRow.classList.add('hidden-by-mode');
} else {
// Ensure row is not hidden by mode if it's selected or no selections exist
// This is handled by the reset at the start of the loop:
// row.classList.remove('hidden-by-mode');
// if (detailsRow) detailsRow.classList.remove('hidden-by-mode');
}
// Always hide details row content in view mode regardless of visibility class
if (detailsRow) {
detailsRow.style.display = 'none';
}
} else if (mode === 'select') { // --- SELECT MODE ---
toggleButton.style.display = 'none';
selectorCheckbox.style.display = 'inline-block';
selectorCheckbox.checked = isSelected;
row.classList.toggle('row-selected', isSelected);
row.classList.remove('view-highlighted'); // Clear view highlight when switching to select
// Always hide details row in select mode
if (detailsRow) detailsRow.style.display = 'none';
// In 'select' mode, no rows should be hidden based on selection status
row.classList.remove('hidden-by-mode');
if (detailsRow) detailsRow.classList.remove('hidden-by-mode');
} else { // --- DETAIL MODE --- (mode === 'detail')
toggleButton.style.display = 'inline-block'; // Show toggle
selectorCheckbox.style.display = 'none';
row.classList.remove('row-selected'); // Clear selection highlight
row.classList.remove('view-highlighted'); // Clear view highlight when switching to detail
// Details row visibility is controlled by the toggle button state, don't force hide/show here
// Ensure main row is visible if not hidden by search
row.classList.remove('hidden-by-mode');
if (detailsRow) {
detailsRow.classList.remove('hidden-by-mode');
// Preserve existing display state (controlled by toggle) unless hidden by search
if (detailsRow.classList.contains('hidden-by-search')) {
detailsRow.style.display = 'none';
}
}
}
// Ensure rows hidden by search remain hidden regardless of mode
if (row.classList.contains('hidden-by-search')) {
row.style.display = 'none';
if (detailsRow) detailsRow.style.display = 'none';
} else if (!row.classList.contains('hidden-by-mode')) {
// Make row visible if not hidden by search or mode
row.style.display = ''; // Or 'table-row' if needed, but '' usually works
} else {
// Row is hidden by mode, ensure it's hidden
row.style.display = 'none';
if (detailsRow) detailsRow.style.display = 'none';
}
});
// Update the leaderboard title based on mode and selection
if (leaderboardTitle) {
if (currentMode === 'view' && selectedRows.size > 0) {
leaderboardTitle.textContent = filteredTitle;
} else {
leaderboardTitle.textContent = defaultTitle;
}
}
// Update the select-all checkbox state after updating the view
updateSelectAllCheckboxState();
// Update cost bars and ticks since visible/selected rows may have changed
updateCostBars();
updateCostTicks();
}
// --- Existing Initializations ---
// Add percentage ticks
const percentCells = document.querySelectorAll('.bar-cell:not(.cost-bar-cell)');
percentCells.forEach(cell => {
// Add ticks at 0%, 10%, 20%, ..., 100%
for (let i = 0; i <= 100; i += 10) {
const tick = document.createElement('div');
tick.className = 'percent-tick';
tick.style.left = `${i}%`;
cell.appendChild(tick);
}
});
// Function to calculate the appropriate max display cost based on visible/selected entries
function calculateDisplayMaxCost() {
// Get the appropriate set of rows based on the current mode and selection state
let rowsToConsider;
if (currentMode === 'view' && selectedRows.size > 0) {
// In view mode with selections, only consider selected rows
rowsToConsider = Array.from(allMainRows).filter(row => {
const rowIndex = row.querySelector('.row-selector')?.dataset.rowIndex;
return rowIndex && selectedRows.has(rowIndex) && !row.classList.contains('hidden-by-search');
});
} else {
// In other modes or without selections, consider all visible rows
rowsToConsider = getVisibleMainRows();
}
// Find the maximum cost among the rows to consider
let maxCost = 0;
rowsToConsider.forEach(row => {
const costBar = row.querySelector('.cost-bar');
if (costBar) {
const cost = parseFloat(costBar.dataset.cost || '0');
if (cost > maxCost) maxCost = cost;
}
});
// Cap at 50 if any entries exceed that amount, otherwise use actual max
return maxCost > 50 ? 50 : Math.max(1, maxCost); // Ensure at least 1 to avoid division by zero
}
// Process cost bars with dynamic scale
function updateCostBars() {
const costBars = document.querySelectorAll('.cost-bar');
const currentMaxDisplayCost = calculateDisplayMaxCost();
// Remove existing special indicators first
document.querySelectorAll('.dark-section, .tear-line').forEach(el => el.remove());
costBars.forEach(bar => {
const cost = parseFloat(bar.dataset.cost);
if (cost > 0) {
// Calculate percentage based on the dynamic display max
const percent = Math.min(cost, currentMaxDisplayCost) / currentMaxDisplayCost * 100;
// Clamp percentage between 0 and 100
bar.style.width = Math.max(0, Math.min(100, percent)) + '%';
// Mark bars that exceed the limit (only if our display max is capped at 50)
if (currentMaxDisplayCost === 50 && cost > 50) {
// Create a darker section at the end with diagonal stripes
const darkSection = document.createElement('div');
darkSection.className = 'bar-viz dark-section';
darkSection.style.width = '15%'; // From 85% to 100%
darkSection.style.left = '85%';
darkSection.style.backgroundColor = 'rgba(13, 110, 253, 0.6)'; // Darker blue
darkSection.style.borderRight = '1px solid rgba(13, 110, 253, 0.8)';
darkSection.style.zIndex = '1';
// Add diagonal stripes with CSS background
darkSection.style.backgroundImage = 'repeating-linear-gradient(45deg, rgba(255,255,255,0.3), rgba(255,255,255,0.3) 5px, transparent 5px, transparent 10px)';
bar.parentNode.appendChild(darkSection);
// Add a dashed "tear line" at the transition point
const tearLine = document.createElement('div');
tearLine.className = 'tear-line';
tearLine.style.position = 'absolute';
tearLine.style.left = '85%';
// Center the tear line vertically and make it 1.5x as tall as the bar
tearLine.style.top = '50%';
tearLine.style.transform = 'translateY(-50%)';
tearLine.style.height = '54px'; // 1.5x the bar height (36px)
tearLine.style.width = '2px';
tearLine.style.backgroundColor = 'white';
tearLine.style.borderLeft = '2px dashed rgba(0, 0, 0, 0.3)';
tearLine.style.zIndex = '2'; // Above the bar
bar.parentNode.appendChild(tearLine);
}
} else {
// Set width to 0 if cost is 0 or negative
bar.style.width = '0%';
}
});
}
// Call this initially to set up the bars
updateCostBars();
// Update cost ticks dynamically based on current max display cost
function updateCostTicks() {
const costCells = document.querySelectorAll('.cost-bar-cell');
if (costCells.length === 0) return;
const currentMaxDisplayCost = calculateDisplayMaxCost();
// Remove existing ticks first
document.querySelectorAll('.cost-tick').forEach(tick => tick.remove());
// Generate appropriate tick values based on current max
let tickValues = [];
// Always use $10 increments, regardless of the max
const maxTickValue = Math.ceil(currentMaxDisplayCost / 10) * 10; // Round up to nearest $10
for (let i = 0; i <= maxTickValue; i += 10) {
tickValues.push(i);
}
// Calculate percentage positions for each tick
const tickPercentages = tickValues.map(tickCost => {
return (tickCost / currentMaxDisplayCost) * 100;
});
// Add tick divs to each cost cell
costCells.forEach(cell => {
const costBar = cell.querySelector('.cost-bar');
// Use optional chaining and provide '0' as fallback if costBar or dataset.cost is missing
const cost = parseFloat(costBar?.dataset?.cost || '0');
// Only add ticks if the cost is actually greater than 0
if (cost > 0) {
tickPercentages.forEach((percent, index) => {
// Ensure percentage is within valid range
if (percent >= 0 && percent <= 100) {
const tick = document.createElement('div');
tick.className = 'cost-tick';
tick.style.left = `${percent}%`;
cell.appendChild(tick);
}
});
}
});
}
// Call this initially to set up the ticks
updateCostTicks();
// --- New Event Listeners ---
// Listener for mode toggle buttons
modeButtons.forEach(button => {
button.addEventListener('click', function(event) {
const newMode = this.dataset.mode;
if (newMode !== currentMode) {
// Update active button style
modeButtons.forEach(btn => {
btn.classList.remove('active');
// Reset specific styles potentially added by .active
btn.style.backgroundColor = '';
btn.style.color = '';
});
this.classList.add('active');
// Apply active styles directly as inline styles might interfere
this.style.backgroundColor = '#e7f3ff'; // Use selected row highlight blue
this.style.color = '#495057'; // Use dark text for contrast on light blue
// Update table view and apply filters
updateTableView(newMode);
applySearchFilter(); // Re-apply search filter when mode changes
}
});
});
// Listener for row selector checkboxes (using event delegation on table body)
const tableBody = document.querySelector('table tbody');
tableBody.addEventListener('change', function(event) {
if (event.target.classList.contains('row-selector') && currentMode === 'select') {
const checkbox = event.target;
const rowIndex = checkbox.dataset.rowIndex;
const mainRow = checkbox.closest('tr');
if (checkbox.checked) {
selectedRows.add(rowIndex);
mainRow.classList.add('row-selected');
} else {
selectedRows.delete(rowIndex);
mainRow.classList.remove('row-selected');
}
// Update select-all checkbox state
updateSelectAllCheckboxState();
// Update cost bars and ticks if in view mode, as selection affects what's shown
if (currentMode === 'view') {
updateCostBars();
updateCostTicks();
}
}
}); // End of tableBody listener
// Listener for Select All checkbox
selectAllCheckbox.addEventListener('change', function() {
if (currentMode !== 'select') return;
const isChecked = selectAllCheckbox.checked;
// Select/deselect only the rows that are currently visible
const visibleRows = getVisibleMainRows();
visibleRows.forEach(row => {
const checkbox = row.querySelector('.row-selector');
const rowIndex = checkbox?.dataset.rowIndex;
if (!checkbox || !rowIndex) return; // Skip if no checkbox/index found
// Only change state if it differs from target state
if (checkbox.checked !== isChecked) {
checkbox.checked = isChecked;
row.classList.toggle('row-selected', isChecked);
if (isChecked) {
selectedRows.add(rowIndex);
} else {
selectedRows.delete(rowIndex);
}
}
});
// After bulk change, ensure the selectAll checkbox state is correct (not indeterminate)
updateSelectAllCheckboxState();
// Update cost bars and ticks after selection changes
updateCostBars();
updateCostTicks();
});
// Listener for search input
searchInput.addEventListener('input', applySearchFilter);
// Add toggle functionality for details (Modified to respect modes)
const toggleButtons = document.querySelectorAll('.toggle-details');
toggleButtons.forEach(button => {
button.addEventListener('click', function() {
// Only allow toggling in 'detail' mode
if (currentMode !== 'detail') return;
const targetId = this.getAttribute('data-target');
const targetRow = document.getElementById(targetId);
const mainRow = this.closest('tr'); // Get the main row associated with this button
if (targetRow && !mainRow.classList.contains('hidden-by-mode') && !mainRow.classList.contains('hidden-by-search')) {
const isVisible = targetRow.style.display !== 'none';
targetRow.style.display = isVisible ? 'none' : 'table-row';
this.textContent = isVisible ? '▶' : '▼';
}
});
});
// Listener for clicking anywhere on a row
tableBody.addEventListener('click', function(event) {
const clickedRow = event.target.closest('tr');
// Ensure it's a main row and not a details row or header/footer
if (!clickedRow || !clickedRow.id.startsWith('main-row-')) return;
// --- START conditional logic ---
if (currentMode === 'select') {
// --- SELECT MODE LOGIC (Existing) ---
// Find the checkbox within this row
const checkbox = clickedRow.querySelector('.row-selector');
if (!checkbox) return; // No checkbox found in this row
// If the click was directly on the checkbox or its label (if any),
// let the default behavior and the 'change' event listener handle it.
// Otherwise, toggle the checkbox state programmatically.
if (event.target !== checkbox && event.target.tagName !== 'LABEL' /* Add if you use labels */) {
checkbox.checked = !checkbox.checked;
// Manually trigger the change event to update state and UI
checkbox.dispatchEvent(new Event('change', { bubbles: true }));
}
// --- END SELECT MODE LOGIC ---
} else if (currentMode === 'view') {
// --- VIEW MODE LOGIC (New) ---
// Don't highlight if the click was on the details toggle button
if (event.target.classList.contains('toggle-details')) {
return;
}
// Toggle the highlight class on the clicked row
clickedRow.classList.toggle('view-highlighted');
// --- END VIEW MODE LOGIC ---
}
// --- END conditional logic ---
});
// --- Initial Setup ---
updateTableView('view'); // Initialize view to 'view' mode
applySearchFilter(); // Apply initial search filter (if any text is pre-filled or just to set initial state)
// Close button functionality
const closeControlsBtn = document.getElementById('close-controls-btn');
if (closeControlsBtn) {
closeControlsBtn.addEventListener('click', function() {
const controlsContainer = document.getElementById('controls-container');
if (controlsContainer) {
controlsContainer.style.display = 'none';
}
});
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -280,6 +280,18 @@ cog.out("```\n")
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
cache_control: true
- name: azure/gpt-4.1
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
reminder: sys
editor_model_name: azure/gpt-4.1-mini
- name: azure/gpt-4.1-mini
edit_format: diff
use_repo_map: true
reminder: sys
- name: azure/o1
edit_format: diff
weak_model_name: azure/gpt-4o-mini
@@ -308,6 +320,18 @@ cog.out("```\n")
editor_model_name: azure/gpt-4o
editor_edit_format: editor-diff
- name: azure/o3
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
streaming: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: azure/o3-mini
edit_format: diff
weak_model_name: azure/gpt-4o-mini
@@ -319,6 +343,66 @@ cog.out("```\n")
accepts_settings:
- reasoning_effort
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: azure/o4-mini
edit_format: diff
weak_model_name: azure/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: azure/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
edit_format: diff
weak_model_name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
@@ -717,6 +801,18 @@ cog.out("```\n")
use_repo_map: true
reminder: sys
- name: gpt-4.1
edit_format: diff
weak_model_name: gpt-4.1-mini
use_repo_map: true
reminder: sys
editor_model_name: gpt-4.1-mini
- name: gpt-4.1-mini
edit_format: diff
use_repo_map: true
reminder: sys
- name: gpt-4.5-preview
edit_format: diff
weak_model_name: gpt-4o-mini
@@ -803,6 +899,17 @@ cog.out("```\n")
editor_model_name: gpt-4o
editor_edit_format: editor-diff
- name: o3
edit_format: diff
weak_model_name: gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
editor_model_name: gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: o3-mini
edit_format: diff
weak_model_name: gpt-4o-mini
@@ -814,6 +921,30 @@ cog.out("```\n")
accepts_settings:
- reasoning_effort
- name: o4-mini
edit_format: diff
weak_model_name: gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openai/gpt-4.1
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
reminder: sys
editor_model_name: openai/gpt-4.1-mini
- name: openai/gpt-4.1-mini
edit_format: diff
use_repo_map: true
reminder: sys
- name: openai/gpt-4.5-preview
edit_format: diff
weak_model_name: gpt-4o-mini
@@ -883,6 +1014,18 @@ cog.out("```\n")
editor_model_name: openai/gpt-4o
editor_edit_format: editor-diff
- name: openai/o3
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
streaming: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openai/o3-mini
edit_format: diff
weak_model_name: gpt-4o-mini
@@ -894,6 +1037,66 @@ cog.out("```\n")
accepts_settings:
- reasoning_effort
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openai/o4-mini
edit_format: diff
weak_model_name: openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openrouter/anthropic/claude-3-opus
edit_format: diff
weak_model_name: openrouter/anthropic/claude-3-5-haiku
@@ -1048,6 +1251,18 @@ cog.out("```\n")
weak_model_name: openrouter/meta-llama/llama-3-70b-instruct
examples_as_sys_msg: true
- name: openrouter/openai/gpt-4.1
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
reminder: sys
editor_model_name: openrouter/openai/gpt-4.1-mini
- name: openrouter/openai/gpt-4.1-mini
edit_format: diff
use_repo_map: true
reminder: sys
- name: openrouter/openai/gpt-4o
edit_format: diff
weak_model_name: openrouter/openai/gpt-4o-mini
@@ -1088,6 +1303,18 @@ cog.out("```\n")
editor_model_name: openrouter/openai/gpt-4o
editor_edit_format: editor-diff
- name: openrouter/openai/o3
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
streaming: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openrouter/openai/o3-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4o-mini
@@ -1110,6 +1337,66 @@ cog.out("```\n")
accepts_settings:
- reasoning_effort
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openrouter/openai/o4-mini
edit_format: diff
weak_model_name: openrouter/openai/gpt-4.1-mini
use_repo_map: true
examples_as_sys_msg: true
use_temperature: false
editor_model_name: openrouter/openai/gpt-4.1
editor_edit_format: editor-diff
system_prompt_prefix: 'Formatting re-enabled. '
accepts_settings:
- reasoning_effort
- name: openrouter/openrouter/optimus-alpha
edit_format: diff
use_repo_map: true
@@ -1131,11 +1418,20 @@ cog.out("```\n")
edit_format: diff
use_repo_map: true
- name: openrouter/x-ai/grok-3-fast-beta
edit_format: diff
use_repo_map: true
- name: openrouter/x-ai/grok-3-mini-beta
use_repo_map: true
accepts_settings:
- reasoning_effort
- name: openrouter/x-ai/grok-3-mini-fast-beta
use_repo_map: true
accepts_settings:
- reasoning_effort
- name: vertex_ai-anthropic_models/vertex_ai/claude-3-7-sonnet@20250219
edit_format: diff
weak_model_name: vertex_ai/claude-3-5-haiku@20241022
@@ -1213,10 +1509,19 @@ cog.out("```\n")
edit_format: diff
use_repo_map: true
- name: xai/grok-3-fast-beta
edit_format: diff
use_repo_map: true
- name: xai/grok-3-mini-beta
use_repo_map: true
accepts_settings:
- reasoning_effort
- name: xai/grok-3-mini-fast-beta
use_repo_map: true
accepts_settings:
- reasoning_effort
```
<!--[[[end]]]-->

View File

@@ -264,13 +264,15 @@ tr:hover { background-color: #f5f5f5; }
</style>
<table>
<tr><th>Model Name</th><th class='right'>Total Tokens</th><th class='right'>Percent</th></tr>
<tr><td>gemini/gemini-2.5-pro-exp-03-25</td><td class='right'>1,119,621</td><td class='right'>77.4%</td></tr>
<tr><td>gemini/gemini-2.5-pro-preview-03-25</td><td class='right'>269,898</td><td class='right'>18.6%</td></tr>
<tr><td>openrouter/anthropic/claude-3.7-sonnet</td><td class='right'>18,140</td><td class='right'>1.3%</td></tr>
<tr><td>o3-mini</td><td class='right'>17,296</td><td class='right'>1.2%</td></tr>
<tr><td>openrouter/x-ai/grok-3-mini-beta</td><td class='right'>16,987</td><td class='right'>1.2%</td></tr>
<tr><td>openrouter/REDACTED</td><td class='right'>4,099</td><td class='right'>0.3%</td></tr>
<tr><td>xai/grok-3-mini-beta</td><td class='right'>1,224</td><td class='right'>0.1%</td></tr>
<tr><td>gemini/gemini-2.5-pro-exp-03-25</td><td class='right'>3,259,444</td><td class='right'>84.4%</td></tr>
<tr><td>openrouter/anthropic/claude-3.7-sonnet</td><td class='right'>534,009</td><td class='right'>13.8%</td></tr>
<tr><td>gemini/gemini-2.5-pro-preview-03-25</td><td class='right'>16,524</td><td class='right'>0.4%</td></tr>
<tr><td>o4-mini</td><td class='right'>16,499</td><td class='right'>0.4%</td></tr>
<tr><td>gpt-4.1-mini</td><td class='right'>11,775</td><td class='right'>0.3%</td></tr>
<tr><td>gpt-4.1</td><td class='right'>10,687</td><td class='right'>0.3%</td></tr>
<tr><td>None</td><td class='right'>8,001</td><td class='right'>0.2%</td></tr>
<tr><td>o3</td><td class='right'>2,521</td><td class='right'>0.1%</td></tr>
<tr><td>openrouter/REDACTED</td><td class='right'>2,058</td><td class='right'>0.1%</td></tr>
</table>
{: .note :}
@@ -288,6 +290,16 @@ by doing something like `git blame` on the repo,
and counting up who wrote all the new lines of code in each release.
Only lines in source code files are counted, not documentation or prompt files.
## Why did aider ignore/discard its proposed edits after it asked to add a new file to the chat?
If aider prompts you to add a new file to the chat and you say yes,
it will re-submit the original request.
The fact that the LLM's reply indicated that it needed to see another file (and you said yes)
is often a sign that the LLM should have been able to see/edit that file in the first place.
Without access to it, there is increased chance that it's done a bad implementation of the requested change.
Often LLMs will hallucinate content for the files they needed but didn't have.
So aider re-submits the original request in this situation.
## Why does aider sometimes stop highlighting code in its replies?
Aider displays the markdown responses that are coming back from the LLM.

View File

@@ -8,100 +8,261 @@ has_children: true
# Aider LLM Leaderboards
Aider works best with LLMs which are good at *editing* code, not just good at writing
code.
To evaluate an LLM's editing skill, aider uses benchmarks that
assess a model's ability to consistently follow the system prompt
to successfully edit code.
Aider excels with LLMs skilled at writing and *editing* code,
and uses benchmarks to
evaluate an LLM's ability to follow instructions and edit code successfully without
human intervention.
[Aider's polyglot benchmark](https://aider.chat/2024/12/21/polyglot.html#the-polyglot-benchmark) tests LLMs on 225 challenging Exercism coding exercises across C++, Go, Java, JavaScript, Python, and Rust.
The leaderboards report the results from a number of popular LLMs.
While [aider can connect to almost any LLM](/docs/llms.html),
it works best with models that score well on the benchmarks.
<h2 id="leaderboard-title">Aider polyglot coding leaderboard</h2>
## Polyglot leaderboard
[Aider's polyglot benchmark](https://aider.chat/2024/12/21/polyglot.html#the-polyglot-benchmark)
asks the LLM to edit source files to complete 225 coding exercises
from Exercism.
It contains exercises in many popular programming languages:
C++, Go, Java, JavaScript, Python and Rust.
The 225 exercises were purposely selected to be the *hardest*
that Exercism offered in those languages, to provide
a strong coding challenge to LLMs.
This benchmark measures the LLM's coding ability in popular languages,
and whether it can
write new code that integrates into existing code.
The model also has to successfully apply all its changes to the source file without human intervention.
<input type="text" id="editSearchInput" placeholder="Search..." style="width: 100%; max-width: 800px; margin: 10px auto; padding: 8px; display: block; border: 1px solid #ddd; border-radius: 4px;">
<div id="controls-container" style="display: flex; align-items: center; width: 100%; max-width: 800px; margin: 10px auto; gap: 10px; box-sizing: border-box; padding: 0 5px; position: relative;">
<input type="text" id="editSearchInput" placeholder="Search..." style="flex-grow: 1; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
<div id="view-mode-toggle" style="display: inline-flex; border: 1px solid #ccc; border-radius: 4px;">
<button id="mode-view-btn" class="mode-button active" data-mode="view" style="padding: 8px 8px; border: none; border-radius: 3px 0 0 3px; cursor: pointer; font-size: 14px; line-height: 1.5; min-width: 50px;">View</button>
<button id="mode-select-btn" class="mode-button" data-mode="select" style="padding: 8px 8px; border: none; background-color: #f8f9fa; border-radius: 0; cursor: pointer; border-left: 1px solid #ccc; font-size: 14px; line-height: 1.5; min-width: 50px;">Select</button>
<button id="mode-detail-btn" class="mode-button" data-mode="detail" style="padding: 8px 8px; border: none; background-color: #f8f9fa; border-radius: 0 3px 3px 0; cursor: pointer; border-left: 1px solid #ccc; font-size: 14px; line-height: 1.5; min-width: 50px;">Detail</button>
</div>
<button id="close-controls-btn" style="width: 18px; height: 18px; padding: 0; border: 1px solid #ddd; border-radius: 50%; background-color: transparent; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 12px; margin-left: 4px; color: #999;">×</button>
</div>
<table style="width: 100%; max-width: 800px; margin: auto; border-collapse: collapse; box-shadow: 0 2px 4px rgba(0,0,0,0.1); font-size: 14px;">
<thead style="background-color: #f2f2f2;">
<tr>
<th style="padding: 8px; width: 40px; text-align: center; vertical-align: middle;">
<input type="checkbox" id="select-all-checkbox" style="display: none; cursor: pointer; vertical-align: middle;">
</th> <!-- Header checkbox added here -->
<th style="padding: 8px; text-align: left;">Model</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;">Cost</th>
<th style="padding: 8px; text-align: center; width: 25%">Percent correct</th>
<th style="padding: 8px; text-align: center; width: 25%">Cost</th>
<th style="padding: 8px; text-align: left;" class="col-command">Command</th>
<th style="padding: 8px; text-align: center; width: 10%" class="col-conform">Correct edit format</th>
<th style="padding: 8px; text-align: left; width: 10%" class="col-edit-format">Edit Format</th>
</tr>
</thead>
<tbody>
{% assign max_cost = 0 %}
{% for row in site.data.polyglot_leaderboard %}
{% if row.total_cost > max_cost %}
{% assign max_cost = row.total_cost %}
{% endif %}
{% endfor %}
{% if max_cost == 0 %}{% assign max_cost = 1 %}{% endif %}
{% assign edit_sorted = site.data.polyglot_leaderboard | sort: 'pass_rate_2' | reverse %}
{% for row in edit_sorted %}
<tr style="border-bottom: 1px solid #ddd;">
<td style="padding: 8px;">{{ row.model }}</td>
<td style="padding: 8px; text-align: center;">{{ row.pass_rate_2 }}%</td>
<td style="padding: 8px; text-align: center;">{{ row.percent_cases_well_formed }}%</td>
<td style="padding: 8px;"><code>{{ row.command }}</code></td>
<td style="padding: 8px; text-align: center;">{{ row.edit_format }}</td>
<td style="padding: 8px; text-align: center;">{% if row.total_cost == 0 %}?{% else %}${{ row.total_cost | times: 1.0 | round: 2 }}{% endif %}</td>
{% for row in edit_sorted %} {% comment %} Add loop index for unique IDs {% endcomment %}
{% assign row_index = forloop.index0 %}
<tr id="main-row-{{ row_index }}">
<td style="padding: 8px; text-align: center; vertical-align: middle;">
<button class="toggle-details" data-target="details-{{ row_index }}" style="background: none; border: none; cursor: pointer; font-size: 16px; padding: 0; vertical-align: middle;">▶</button>
<input type="checkbox" class="row-selector" data-row-index="{{ row_index }}" style="display: none; cursor: pointer; vertical-align: middle;">
</td>
<td style="padding: 8px;"><span>{{ row.model }}</span></td>
<td class="bar-cell">
<div class="bar-viz" style="width: {{ row.pass_rate_2 }}%; background-color: rgba(40, 167, 69, 0.3); border-right: 1px solid rgba(40, 167, 69, 0.5);"></div>
<span>{{ row.pass_rate_2 }}%</span>
</td>
<td class="bar-cell cost-bar-cell">
{% if row.total_cost > 0 %}
<div class="bar-viz cost-bar" data-cost="{{ row.total_cost }}" data-max-cost="{{ max_cost }}" style="width: 0%; background-color: rgba(13, 110, 253, 0.3); border-right: 1px solid rgba(13, 110, 253, 0.5);"></div>
{% endif %}
{% assign rounded_cost = row.total_cost | times: 1.0 | round: 2 %}
<span>{% if row.total_cost == 0 or rounded_cost == 0.00 %}{% else %}${{ rounded_cost }}{% endif %}</span>
</td>
<td style="padding: 8px;" class="col-command"><span><code>{{ row.command }}</code></span></td>
<td style="padding: 8px; text-align: center;" class="col-conform"><span>{{ row.percent_cases_well_formed }}%</span></td>
<td style="padding: 8px;" class="col-edit-format"><span>{{ row.edit_format }}</span></td>
</tr>
<tr class="details-row" id="details-{{ row_index }}" style="display: none; background-color: #f9f9f9;">
<td colspan="7" style="padding: 15px; border-bottom: 1px solid #ddd;">
<ul style="margin: 0; padding-left: 20px; list-style: none; border-bottom: 1px solid #ddd;">
{% for pair in row %}
{% if pair[1] != "" and pair[1] != nil %}
<li><strong>
{% if pair[0] == 'percent_cases_well_formed' %}
Percent cases well formed
{% else %}
{{ pair[0] | replace: '_', ' ' | capitalize }}
{% endif %}
:</strong>
{% if pair[0] == 'command' %}<code>{{ pair[1] }}</code>{% else %}{{ pair[1] }}{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
### Aider polyglot benchmark results
<canvas id="editChart" width="800" height="450" style="margin-top: 20px"></canvas>
<script src="https://unpkg.com/patternomaly/dist/patternomaly.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
{% assign data_source = edit_sorted %}
{% assign pass_rate_field = "pass_rate_2" %}
{% assign highlight_model = "xxxxxx" %}
{% include leaderboard.js %}
</script>
<style>
#leaderboard-title {
margin-bottom: 20px; /* Add space below the title */
}
tr.selected {
color: #0056b3;
}
table {
table-layout: fixed;
}
thead {
border-top: 1px solid #ddd; /* Add top border to header */
}
td, th {
border: none; /* Remove internal cell borders */
word-wrap: break-word;
overflow-wrap: break-word;
vertical-align: middle; /* Ensure consistent vertical alignment */
}
td:nth-child(3), td:nth-child(4) {
font-size: 12px;
tbody tr {
height: 50px; /* Set a minimum height for all data rows */
}
/* Hide command and edit format columns on mobile */
td.col-command { /* Command column */
font-size: 12px; /* Keep font size adjustment for command column if desired, or remove */
}
/* Hide new columns first on smaller screens */
@media screen and (max-width: 991px) {
th.col-conform, td.col-conform,
th.col-edit-format, td.col-edit-format {
display: none;
}
/* Increase width of Percent correct and Cost columns when others are hidden */
th:nth-child(3), td:nth-child(3), /* Percent correct */
th:nth-child(4), td:nth-child(4) { /* Cost */
width: 33% !important; /* Override inline style */
}
}
/* Hide command column on even smaller screens */
@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 */
th.col-command, td.col-command { /* Command column */
display: none;
}
}
/* --- Control Styles --- */
#controls-container {
margin-bottom: 20px; /* Add some space below controls */
}
#editSearchInput, #view-mode-select {
padding: 8px 12px; /* Consistent padding */
border: 1px solid #ccc; /* Slightly softer border */
border-radius: 4px;
font-size: 14px; /* Match table font size */
height: 38px; /* Match height */
box-sizing: border-box; /* Include padding/border in height */
}
.bar-cell {
position: relative; /* Positioning context for the bar */
padding: 8px;
/* text-align: center; Removed */
overflow: hidden; /* Prevent bar from overflowing cell boundaries if needed */
}
.cost-bar-cell {
background-image: none; /* Remove default gradient for cost cells */
}
.percent-tick, .cost-tick {
position: absolute;
top: 50%;
transform: translateY(10px);
height: 8px; /* Short tick */
width: 1px;
background-color: rgba(170, 170, 170, 0.5);
z-index: 2; /* Above the bar but below the text */
}
.bar-viz {
position: absolute;
left: 0;
top: 50%; /* Position at the middle of the cell */
transform: translateY(-50%); /* Center the bar vertically */
z-index: 1; /* Above background, below ticks and text */
height: 36px;
border-radius: 0 2px 2px 0; /* Slightly rounded end corners */
/* Width and colors are set inline via style attribute */
}
/* Add a tooltip class for showing cost information on hover */
.cost-bar-cell:hover .bar-viz[style*="background-image"] {
animation: stripe-animation 2s linear infinite;
}
@keyframes stripe-animation {
0% { background-position: 0 0; }
100% { background-position: 20px 0; }
}
.bar-cell span {
position: absolute; /* Position relative to the cell */
left: 5px; /* Position slightly inside the left edge */
top: 50%; /* Center vertically */
transform: translateY(-50%); /* Adjust vertical centering */
z-index: 3; /* Ensure text is above everything else */
background-color: rgba(255, 255, 255, 0.7); /* Semi-transparent white background */
padding: 0 4px; /* Add padding around the text */
border-radius: 3px; /* Rounded corners for the text background */
font-size: 14px; /* Adjust font size for the numbers */
}
.toggle-details {
color: #888; /* Make toggle symbol more subtle */
transition: color 0.2s; /* Smooth transition on hover */
}
/* Style for selected rows */
tr.row-selected > td {
background-color: #e7f3ff; /* Example light blue highlight */
}
/* Ensure checkbox is vertically aligned if needed */
.row-selector {
vertical-align: middle;
}
/* Hide rows not matching the filter */
tr.hidden-by-mode {
display: none !important; /* Use important to override other display styles if necessary */
}
tr.hidden-by-search {
display: none !important;
}
/* --- Mode Toggle Button Styles --- */
#view-mode-toggle {
height: 38px; /* Match input height */
box-sizing: border-box;
flex-shrink: 0; /* Prevent toggle from shrinking on small screens */
}
.mode-button {
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
white-space: nowrap; /* Prevent text wrapping */
}
.mode-button:not(.active) {
background-color: #f8f9fa; /* Light grey background */
color: #495057; /* Dark grey text */
}
.mode-button:not(.active):hover {
background-color: #e2e6ea; /* Slightly darker grey on hover */
}
/* Style for highlighted rows in view mode */
tr.view-highlighted > td {
background-color: #fffef5; /* Very light yellow/cream */
/* Border moved to specific cell below */
}
/* Apply border and adjust padding ONLY for the first *visible* cell (Model name) in view mode */
tr.view-highlighted > td:nth-child(2) {
border-left: 4px solid #ffc107; /* Warning yellow border */
/* Original padding is 8px. Subtract border width. */
padding-left: 4px;
}
</style>
<script>
{% include leaderboard_table.js %}
</script>
<p class="post-date">
<p class="post-date" style="margin-top: 20px;">
By Paul Gauthier,
last updated
<!--[[[cog
@@ -124,6 +285,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.')}")
]]]-->
April 12, 2025.
April 16, 2025.
<!--[[[end]]]-->
</p>

View File

@@ -9,16 +9,37 @@ You'll need a [xAI API key](https://console.x.ai.).
To use xAI:
```
python -m pip install -U aider-chat
```bash
python -m pip install aider-install
aider-install
export XAI_API_KEY=<key> # Mac/Linux
setx XAI_API_KEY <key> # Windows, restart shell after setx
aider --model xai/grok-beta
# Grok 3
aider --model xai/grok-3-beta
# Grok 3 fast (faster, more expensive)
aider --model xai/grok-3-fast-beta
# Grok 3 Mini
aider --model xai/grok-3-mini-beta
# Grok 3 Mini fast (faster, more expensive)
aider --model xai/grok-3-mini-fast-beta
# List models available from xAI
aider --list-models xai/
```
The Grok 3 Mini models support the `--reasoning-effort` flag.
See the [reasoning settings documentation](../config/reasoning.md) for details.
Example:
```bash
aider --model xai/grok-3-mini-beta --reasoning-effort high
```

View File

@@ -73,7 +73,7 @@ cog.out(text)
</a>
<a href="https://pypi.org/project/aider-chat/" class="github-badge badge-installs" title="Total number of installations via pip from PyPI">
<span class="badge-label">📦 Installs</span>
<span class="badge-value">1.9M</span>
<span class="badge-value">2.0M</span>
</a>
<div class="github-badge badge-tokens" title="Number of tokens processed weekly by Aider users">
<span class="badge-label">📈 Tokens/week</span>
@@ -85,7 +85,7 @@ cog.out(text)
</a>
<a href="/HISTORY.html" class="github-badge badge-coded" title="Percentage of the new code in Aider's last release written by Aider itself">
<span class="badge-label">🔄 Singularity</span>
<span class="badge-value">86%</span>
<span class="badge-value">92%</span>
</a>
<!--[[[end]]]-->
</div>
@@ -268,6 +268,11 @@ cog.out(text)
]]]-->
<script>
const testimonials = [
{
text: "My life has changed this week. There's finally an AI coding tool that's good enough to keep up with me... Aider... It's going to rock your world.",
author: "Eric S. Raymond",
link: "https://x.com/esrtweet/status/1910809356381413593"
},
{
text: "The best free open source AI coding assistant.",
author: "IndyDevDan",
@@ -412,6 +417,26 @@ const testimonials = [
text: "Cannot believe aider vibe coded a 650 LOC feature across service and cli today in 1 shot.",
author: "autopoietist",
link: "https://discord.com/channels/1131200896827654144/1131200896827654149/1355675042259796101"
},
{
text: "Oh no the secret is out! Yes, Aider is the best coding tool around. I highly, highly recommend it to anyone.",
author: "Joshua D Vander Hook",
link: "https://x.com/jodavaho/status/1911154899057795218"
},
{
text: "thanks to aider, i have started and finished three personal projects within the last two days",
author: "joseph stalzyn",
link: "https://x.com/anitaheeder/status/1908338609645904160"
},
{
text: "Been using aider as my daily driver for over a year ... I absolutely love the tool, like beyond words.",
author: "koleok",
link: "https://discord.com/channels/1131200896827654144/1273248471394291754/1356727448372252783"
},
{
text: "aider is really cool",
author: "kache (@yacineMTB)",
link: "https://x.com/yacineMTB/status/1911224442430124387"
}
];
</script>