mirror of
https://github.com/Aider-AI/aider
synced 2026-05-05 06:32:04 +02:00
Compare commits
595 Commits
v0.63.1.de
...
v0.66.1.de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c62dde4c9c | ||
|
|
3fef1babcb | ||
|
|
16af1751a6 | ||
|
|
b0e138952e | ||
|
|
1271c037ef | ||
|
|
36b59ba617 | ||
|
|
b671db7108 | ||
|
|
9304b80b69 | ||
|
|
03c2964364 | ||
|
|
49c78f2797 | ||
|
|
1a8d112055 | ||
|
|
7b193d693f | ||
|
|
e8fa5c36c2 | ||
|
|
a6e162c37a | ||
|
|
9c55b7a317 | ||
|
|
4ef4e8cd72 | ||
|
|
e9942737c6 | ||
|
|
5c208dba41 | ||
|
|
ba032ce60e | ||
|
|
2fe0dda8af | ||
|
|
97daff4a10 | ||
|
|
caeceb58a5 | ||
|
|
3739d48e52 | ||
|
|
858fdb02ec | ||
|
|
b0cbb071e6 | ||
|
|
f222739b0d | ||
|
|
a280f5d5b2 | ||
|
|
cef333a01c | ||
|
|
24bd016a1a | ||
|
|
3c44f824cb | ||
|
|
3ee78ef557 | ||
|
|
d9b1bcbdcc | ||
|
|
283dd0b1f1 | ||
|
|
56345ddef9 | ||
|
|
4631008f8c | ||
|
|
e2ebde75be | ||
|
|
91613fcbf7 | ||
|
|
0b279143cc | ||
|
|
ade4847c61 | ||
|
|
a3e7203331 | ||
|
|
bbabd38a48 | ||
|
|
eb996c1e42 | ||
|
|
bf0ad4cda1 | ||
|
|
c32af6536a | ||
|
|
2437f9b051 | ||
|
|
0b781174bd | ||
|
|
f448d3e2db | ||
|
|
6b4222ec48 | ||
|
|
3f770cc5c0 | ||
|
|
14902f5b9a | ||
|
|
efdeb13bf5 | ||
|
|
62558291b6 | ||
|
|
edb0120bbf | ||
|
|
0dbaec553f | ||
|
|
295040c94c | ||
|
|
c1c4193b1d | ||
|
|
d17f0a9e1f | ||
|
|
871030dadb | ||
|
|
0ee9b74c0f | ||
|
|
82929f650c | ||
|
|
37b31c46bd | ||
|
|
c682bd858a | ||
|
|
2439891ee0 | ||
|
|
23825cafe7 | ||
|
|
a8f6f1fce2 | ||
|
|
e11faadf39 | ||
|
|
2c7251f4b9 | ||
|
|
fb9f18fc9c | ||
|
|
93cd3d0d8b | ||
|
|
ed2479ea82 | ||
|
|
accde0bfd0 | ||
|
|
7b34d9e4f4 | ||
|
|
6af71951af | ||
|
|
3eed45dc3e | ||
|
|
320b059bc7 | ||
|
|
a89ce06377 | ||
|
|
e4a1d6fe89 | ||
|
|
93c625bb81 | ||
|
|
87f84fb82d | ||
|
|
ce9e76a7dc | ||
|
|
4f3f1c5e23 | ||
|
|
22076d401f | ||
|
|
79ea82f147 | ||
|
|
3785415632 | ||
|
|
35eda73ad1 | ||
|
|
c8282fc8d3 | ||
|
|
5030881934 | ||
|
|
bc1e3a7059 | ||
|
|
ba17dceb4d | ||
|
|
62109f4ab1 | ||
|
|
d54fbd6592 | ||
|
|
a1f5bfb746 | ||
|
|
3ab1018c66 | ||
|
|
62e96372fa | ||
|
|
945d10f554 | ||
|
|
f44e5ae5f9 | ||
|
|
a67b665846 | ||
|
|
8fb23b414c | ||
|
|
f5100626a8 | ||
|
|
9ab46fade7 | ||
|
|
2ce01b157b | ||
|
|
f714e42e11 | ||
|
|
447b7af573 | ||
|
|
ec2b635a1a | ||
|
|
7465b4bf91 | ||
|
|
4580fac6fa | ||
|
|
8c218e9edc | ||
|
|
44ceb8f1a0 | ||
|
|
642c1c50fb | ||
|
|
4de8c25a3f | ||
|
|
565f08a8e9 | ||
|
|
a85ae206c9 | ||
|
|
9e9b5e8d46 | ||
|
|
b623141a8f | ||
|
|
631cdc37c4 | ||
|
|
8d50bc0ef1 | ||
|
|
ae395fbb8f | ||
|
|
10877a99f1 | ||
|
|
0faff91c72 | ||
|
|
00f79fecd0 | ||
|
|
203128d935 | ||
|
|
4f6e52aed0 | ||
|
|
7bc7b2e3da | ||
|
|
27f0ca3b08 | ||
|
|
2337b2bb3e | ||
|
|
48ea13e130 | ||
|
|
5c73ab26c0 | ||
|
|
947e4ce71d | ||
|
|
200295e3ee | ||
|
|
ded5fe5ec0 | ||
|
|
7dffa943fa | ||
|
|
f702f67e27 | ||
|
|
a64956406d | ||
|
|
9c8bde2cff | ||
|
|
70a282ebf1 | ||
|
|
415652d38e | ||
|
|
1a745e4fa9 | ||
|
|
973e86df27 | ||
|
|
1f2917681f | ||
|
|
28d1feacf5 | ||
|
|
cf4ef8605d | ||
|
|
4be3728273 | ||
|
|
34b8c3f47c | ||
|
|
309893fd1e | ||
|
|
705eb06e8d | ||
|
|
5cfcf255e9 | ||
|
|
b8f36c8277 | ||
|
|
73c1dc697f | ||
|
|
a9c4647461 | ||
|
|
aaeaa24153 | ||
|
|
b2232cda7b | ||
|
|
3ba4aca268 | ||
|
|
f45533e20b | ||
|
|
2e7c5d6cfa | ||
|
|
476acc7715 | ||
|
|
ab3b50296c | ||
|
|
60c29b2839 | ||
|
|
7972f5f4bc | ||
|
|
83a6865eb3 | ||
|
|
29a9b650ed | ||
|
|
dd48b740f9 | ||
|
|
401ce7a63d | ||
|
|
8218d085f7 | ||
|
|
554d274fff | ||
|
|
13318219db | ||
|
|
61759f984c | ||
|
|
a73e77a819 | ||
|
|
b5f1659382 | ||
|
|
beb6722f57 | ||
|
|
a052b89152 | ||
|
|
95b391350f | ||
|
|
5773eac03f | ||
|
|
da4ace2875 | ||
|
|
e507c5b502 | ||
|
|
722c2c2668 | ||
|
|
8e7bfef9f1 | ||
|
|
1811f0d0d5 | ||
|
|
6b9d534fe2 | ||
|
|
dc4562a845 | ||
|
|
c15af63bc9 | ||
|
|
5b68c2c7d9 | ||
|
|
b70e0bd1f6 | ||
|
|
743f0f5540 | ||
|
|
e647a5b733 | ||
|
|
df1d259e42 | ||
|
|
e3efab7fbf | ||
|
|
cd79f7f4b0 | ||
|
|
5d175745bf | ||
|
|
e648bac74b | ||
|
|
e5c0ebd0a0 | ||
|
|
608a43402c | ||
|
|
75bc2dd564 | ||
|
|
bbd81c3cf7 | ||
|
|
301eb7c74d | ||
|
|
a756039f27 | ||
|
|
b4d1b71ee7 | ||
|
|
8d85a4754d | ||
|
|
a1b48049a9 | ||
|
|
6789844c1f | ||
|
|
c602a839ca | ||
|
|
01c7793e90 | ||
|
|
47b013b034 | ||
|
|
dc2047804a | ||
|
|
885e5cbd7c | ||
|
|
635a5196e8 | ||
|
|
cbd339190b | ||
|
|
266093189d | ||
|
|
62b02d4370 | ||
|
|
8546a1dc86 | ||
|
|
ae98bf237f | ||
|
|
0398deb005 | ||
|
|
3a1492977b | ||
|
|
ef40a456e8 | ||
|
|
583b78c0c1 | ||
|
|
c0988de581 | ||
|
|
34a190e29b | ||
|
|
0940598708 | ||
|
|
7e6cbb3efa | ||
|
|
7dc4e00c75 | ||
|
|
8a598eacaf | ||
|
|
8592fad9cd | ||
|
|
fa72a89d35 | ||
|
|
5e99c51d93 | ||
|
|
905976e765 | ||
|
|
3ebd47d3db | ||
|
|
bf4c7c475a | ||
|
|
bf38371971 | ||
|
|
18460f4f91 | ||
|
|
f94e3e6aba | ||
|
|
1647da2942 | ||
|
|
86e2cdb1fb | ||
|
|
764702a377 | ||
|
|
837a97ffdf | ||
|
|
217e9b96d8 | ||
|
|
524274fcf4 | ||
|
|
6d5f576b92 | ||
|
|
445f9fa7df | ||
|
|
2ff3a23606 | ||
|
|
c5ce57ea7f | ||
|
|
351b8e50f0 | ||
|
|
68be6c5742 | ||
|
|
7a34a2dfa9 | ||
|
|
49ce9e1209 | ||
|
|
c84e192324 | ||
|
|
d696673f07 | ||
|
|
2957d463c9 | ||
|
|
af48e50898 | ||
|
|
f4b964a4b8 | ||
|
|
a79ce7a151 | ||
|
|
21bb83c55a | ||
|
|
7122ceb16c | ||
|
|
f9bcfe341c | ||
|
|
13c5bfdd88 | ||
|
|
bf79c2cb99 | ||
|
|
325cdfcf57 | ||
|
|
7d14d4ade9 | ||
|
|
1b7d12194e | ||
|
|
91f238aded | ||
|
|
78ff489995 | ||
|
|
ff791439e2 | ||
|
|
3f8b2d6b99 | ||
|
|
4dcbce58ed | ||
|
|
0427deb897 | ||
|
|
f3eb3409e3 | ||
|
|
86619052ca | ||
|
|
0c59d3234e | ||
|
|
939d7ea3fb | ||
|
|
dc8761763d | ||
|
|
4894914db1 | ||
|
|
aee94a0584 | ||
|
|
c550422168 | ||
|
|
cebd9cabb3 | ||
|
|
3f16652d56 | ||
|
|
2ebf48ca71 | ||
|
|
c2f184f5bb | ||
|
|
e56651e5c0 | ||
|
|
1d09e96127 | ||
|
|
73de0ea8be | ||
|
|
757eac0579 | ||
|
|
bb78e2f57f | ||
|
|
92579243c5 | ||
|
|
8d0ba40d67 | ||
|
|
ff8c1aace9 | ||
|
|
cf74dc9b48 | ||
|
|
e63df83091 | ||
|
|
14522dbbcd | ||
|
|
91daea9e01 | ||
|
|
12b789fc4e | ||
|
|
baa13351a6 | ||
|
|
8f83204f0f | ||
|
|
80f5b60e1d | ||
|
|
54525f6696 | ||
|
|
3dc50216b5 | ||
|
|
324430a696 | ||
|
|
65d7957610 | ||
|
|
6ac4993cf2 | ||
|
|
100744a952 | ||
|
|
3a331e55dc | ||
|
|
a57f81ba5f | ||
|
|
ca0b55fbbf | ||
|
|
38a3cf98dd | ||
|
|
1234ad92e5 | ||
|
|
488edc24ce | ||
|
|
307c23631a | ||
|
|
83d2241883 | ||
|
|
f9126416e8 | ||
|
|
4e9ae16cb3 | ||
|
|
ef8bfdffa7 | ||
|
|
bfb090331f | ||
|
|
5506d0f25b | ||
|
|
6ebd2d0883 | ||
|
|
a16dcaba4e | ||
|
|
f06452c6c5 | ||
|
|
6a0a97cb41 | ||
|
|
711102b438 | ||
|
|
6d53eb0aaa | ||
|
|
0ccf04a2c5 | ||
|
|
070ce35b44 | ||
|
|
a8296e5de5 | ||
|
|
d17f25e975 | ||
|
|
23095ada85 | ||
|
|
f9ef161991 | ||
|
|
28004bae2f | ||
|
|
17aef7be7d | ||
|
|
ebba8f5110 | ||
|
|
dbd7f51f5c | ||
|
|
fbadfcfa7c | ||
|
|
2c12234604 | ||
|
|
13cb6a315c | ||
|
|
48e7376002 | ||
|
|
60d82eddee | ||
|
|
30ee89c7e9 | ||
|
|
25bcea6aec | ||
|
|
488c88da91 | ||
|
|
8fdcd92260 | ||
|
|
781a40df52 | ||
|
|
2412c81d92 | ||
|
|
a7fc0f9d2e | ||
|
|
9eab021a50 | ||
|
|
c189a52e5e | ||
|
|
6d6d763dd3 | ||
|
|
3cfbaa0ed6 | ||
|
|
e1b4571fdf | ||
|
|
08027ea9c4 | ||
|
|
d0528a00c1 | ||
|
|
7ae6a2ba9a | ||
|
|
ad0e5c4770 | ||
|
|
51b181d5fb | ||
|
|
2785b0a857 | ||
|
|
45a113ff9e | ||
|
|
cee59c2ca3 | ||
|
|
5cb9b242e2 | ||
|
|
1ed48de928 | ||
|
|
c4e4bc71ed | ||
|
|
ed0763706b | ||
|
|
1c79d517fc | ||
|
|
1a7a2f3088 | ||
|
|
4199789786 | ||
|
|
c9b0941d1f | ||
|
|
3d544136d2 | ||
|
|
8448eff1eb | ||
|
|
a3dde4599a | ||
|
|
3d7440c673 | ||
|
|
8f41006eba | ||
|
|
7d1379fe9f | ||
|
|
ced4f9f0d9 | ||
|
|
7fba332f58 | ||
|
|
8eda09533d | ||
|
|
6c42ee4edf | ||
|
|
3053595bfe | ||
|
|
6cf78d1a3f | ||
|
|
6c0ee9d917 | ||
|
|
50051dbfd5 | ||
|
|
30a8c5e12e | ||
|
|
4498549783 | ||
|
|
2ce3fedbfc | ||
|
|
8e10be665c | ||
|
|
80636cb8aa | ||
|
|
1b893da07d | ||
|
|
2f8aa3471b | ||
|
|
92a6957f0b | ||
|
|
d7248b11e5 | ||
|
|
6f4ed00105 | ||
|
|
347b299bbc | ||
|
|
614d297f22 | ||
|
|
59d0fe00c3 | ||
|
|
d6ebdff28f | ||
|
|
0ec16d0eab | ||
|
|
3906894fde | ||
|
|
a43772b21d | ||
|
|
cd81c2619b | ||
|
|
5abadc31a3 | ||
|
|
87654b698b | ||
|
|
2a1d2ef294 | ||
|
|
2a387707ef | ||
|
|
ce68062290 | ||
|
|
1b9073b085 | ||
|
|
e94961a14f | ||
|
|
d4e77b3be4 | ||
|
|
b96b36d5ea | ||
|
|
72d559a92c | ||
|
|
9a7bdcb6db | ||
|
|
2e4cf48e7e | ||
|
|
b78f8abeb4 | ||
|
|
7aa4e44317 | ||
|
|
2619b92131 | ||
|
|
28be59582f | ||
|
|
f96cc03587 | ||
|
|
cbd35b0e87 | ||
|
|
443acbe4b5 | ||
|
|
1f0d26e8c7 | ||
|
|
8302e9d0dd | ||
|
|
c797af020a | ||
|
|
1c85afa320 | ||
|
|
eb5317f8e5 | ||
|
|
8b860615b8 | ||
|
|
c15ac341e2 | ||
|
|
c2c7ee1047 | ||
|
|
72c46ccec6 | ||
|
|
dd3bfaee01 | ||
|
|
03206ad90e | ||
|
|
2e00307190 | ||
|
|
b3e29ab20e | ||
|
|
5504ac535b | ||
|
|
4b3dd7f4ea | ||
|
|
8edf9540d5 | ||
|
|
1c62ecd1b5 | ||
|
|
7cf3d9f3ce | ||
|
|
9b5a703307 | ||
|
|
370993cbed | ||
|
|
ddc538cdfa | ||
|
|
062dc43c87 | ||
|
|
7d9b986c04 | ||
|
|
bd2b9a12ed | ||
|
|
2b55707738 | ||
|
|
093540507e | ||
|
|
8f1dcfda07 | ||
|
|
16b319174b | ||
|
|
35115f5707 | ||
|
|
e9e51db9c7 | ||
|
|
ec39f018e2 | ||
|
|
59f4a3bcc7 | ||
|
|
1a8949eea3 | ||
|
|
fa85bdceed | ||
|
|
6b703244ec | ||
|
|
1a1cb0d3f1 | ||
|
|
95c9863d0a | ||
|
|
82187f6a71 | ||
|
|
75f52a1324 | ||
|
|
6e076a40a9 | ||
|
|
ded60036cb | ||
|
|
539a6cde63 | ||
|
|
3a28e74d89 | ||
|
|
c93f3faed9 | ||
|
|
1aaa3d9279 | ||
|
|
a06a9ed7d8 | ||
|
|
18a88596a6 | ||
|
|
2ac077603b | ||
|
|
3bb8b163b8 | ||
|
|
aac45097ca | ||
|
|
788956e86d | ||
|
|
e917424f5d | ||
|
|
1f6a5d04d9 | ||
|
|
dba844c7f9 | ||
|
|
09c11ef8ad | ||
|
|
ff21669bb5 | ||
|
|
a059ca2537 | ||
|
|
f4531b9434 | ||
|
|
05b350ac4b | ||
|
|
cfba315a85 | ||
|
|
12188b6684 | ||
|
|
725b2fc16f | ||
|
|
90a28e31e8 | ||
|
|
c057b00e08 | ||
|
|
b0c0104ba3 | ||
|
|
855b184e91 | ||
|
|
bc88242dc0 | ||
|
|
6357cd623f | ||
|
|
d3e7d20e30 | ||
|
|
7b568c2df3 | ||
|
|
2bff0522e8 | ||
|
|
77e180171c | ||
|
|
1e8fc97ba4 | ||
|
|
a799851832 | ||
|
|
2c81105bfc | ||
|
|
bf99ac56a0 | ||
|
|
8bfb47948a | ||
|
|
b8c41198a3 | ||
|
|
fe138ac05b | ||
|
|
bed62fdcb5 | ||
|
|
f068df0297 | ||
|
|
6a05e34d20 | ||
|
|
8b69b9c6a4 | ||
|
|
10192296fe | ||
|
|
7b98db2f7d | ||
|
|
81696c2e7a | ||
|
|
16a4f823bd | ||
|
|
39bbfc56a4 | ||
|
|
308c49b2d8 | ||
|
|
53e46a9251 | ||
|
|
6075b3dc33 | ||
|
|
860a828973 | ||
|
|
033eaa36c6 | ||
|
|
b3566f5449 | ||
|
|
f1306d3301 | ||
|
|
cc18441435 | ||
|
|
7e787d93e6 | ||
|
|
b08f444e74 | ||
|
|
09c1acdbe2 | ||
|
|
7a4a956eff | ||
|
|
aabbf5a72f | ||
|
|
5ed44bb174 | ||
|
|
92cf2cbd47 | ||
|
|
34aff6c786 | ||
|
|
11f10e586a | ||
|
|
a31feae2bd | ||
|
|
3517d58f01 | ||
|
|
9d13fadd41 | ||
|
|
c1febce528 | ||
|
|
e0aadbd961 | ||
|
|
7b9a76c5ea | ||
|
|
6133fa8384 | ||
|
|
67cc215ed3 | ||
|
|
ea4ad2ea4d | ||
|
|
847454a4f7 | ||
|
|
8cba1fdd71 | ||
|
|
e56112739c | ||
|
|
76988b746f | ||
|
|
32eb365a0b | ||
|
|
2c5feddad5 | ||
|
|
210500ff3e | ||
|
|
7c8f10e832 | ||
|
|
644da2f9e4 | ||
|
|
2a80d9c555 | ||
|
|
76f8791f3c | ||
|
|
c51a013109 | ||
|
|
88c2f95ea5 | ||
|
|
062fa7de78 | ||
|
|
d6c1a41e8d | ||
|
|
20ab5f9326 | ||
|
|
ab5a8b24a5 | ||
|
|
21a28623ca | ||
|
|
06a5fec612 | ||
|
|
46ecb8a663 | ||
|
|
3c9c6eef6e | ||
|
|
72734de376 | ||
|
|
a20ea09a6e | ||
|
|
4bd7bce232 | ||
|
|
8adf42216d | ||
|
|
5f40aaabb5 | ||
|
|
5295abbb83 | ||
|
|
201abe1524 | ||
|
|
6d26051d11 | ||
|
|
4613bf78d5 | ||
|
|
1f8fdc6f5c | ||
|
|
abf804cf10 | ||
|
|
d7a195706f | ||
|
|
569370109a | ||
|
|
eae3f04c83 | ||
|
|
ee0987f331 | ||
|
|
bdafa842bd | ||
|
|
76c7c2562c | ||
|
|
f7de2234f2 | ||
|
|
c725c45726 | ||
|
|
383bef456d | ||
|
|
7f48f3d01d | ||
|
|
0bf17a48f7 | ||
|
|
c127f8f2f0 | ||
|
|
d4d5d15e18 | ||
|
|
b254afa498 | ||
|
|
0ce5a94c15 | ||
|
|
38a5405c65 | ||
|
|
ecef784686 | ||
|
|
e82b2c12b4 | ||
|
|
3c26ced8db | ||
|
|
2681a41abb | ||
|
|
805deb1002 | ||
|
|
6b792de802 | ||
|
|
26f8e34dcb | ||
|
|
e0c1b2458c | ||
|
|
66f94d2141 | ||
|
|
503a9a0038 | ||
|
|
d8a5bc3ae9 | ||
|
|
94c3957d92 | ||
|
|
266350b8ce | ||
|
|
721d852cc7 | ||
|
|
ffbf205aba | ||
|
|
e1a1e43c3a | ||
|
|
c538817b61 | ||
|
|
71d85d2771 | ||
|
|
fef1b59b42 | ||
|
|
8801fda972 | ||
|
|
a8a3e2401b | ||
|
|
a7f59a2e2b | ||
|
|
d8e9da35d6 |
2
.github/workflows/docker-build-test.yml
vendored
2
.github/workflows/docker-build-test.yml
vendored
@@ -24,6 +24,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
2
.github/workflows/docker-release.yml
vendored
2
.github/workflows/docker-release.yml
vendored
@@ -12,6 +12,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
4
.github/workflows/pages.yml
vendored
4
.github/workflows/pages.yml
vendored
@@ -36,7 +36,9 @@ jobs:
|
||||
working-directory: aider/website
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -12,6 +12,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
|
||||
9
.github/workflows/ubuntu-tests.yml
vendored
9
.github/workflows/ubuntu-tests.yml
vendored
@@ -25,12 +25,19 @@ jobs:
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libportaudio2
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
@@ -38,5 +45,7 @@ jobs:
|
||||
pip install .
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
AIDER_ANALYTICS: false
|
||||
run: |
|
||||
pytest
|
||||
|
||||
4
.github/workflows/windows-tests.yml
vendored
4
.github/workflows/windows-tests.yml
vendored
@@ -25,6 +25,8 @@ jobs:
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
@@ -38,6 +40,8 @@ jobs:
|
||||
pip install .
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
AIDER_ANALYTICS: false
|
||||
run: |
|
||||
pytest
|
||||
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -11,4 +11,6 @@ _site
|
||||
.jekyll-cache/
|
||||
.jekyll-metadata
|
||||
aider/__version__.py
|
||||
.venv/
|
||||
aider/_version.py
|
||||
.venv/
|
||||
.gitattributes
|
||||
|
||||
@@ -187,8 +187,8 @@ pytest
|
||||
You can also run specific test files or test cases by providing the file path or test name:
|
||||
|
||||
```
|
||||
pytest aider/tests/test_coder.py
|
||||
pytest aider/tests/test_coder.py::TestCoder::test_specific_case
|
||||
pytest tests/basic/test_coder.py
|
||||
pytest tests/basic/test_coder.py::TestCoder::test_specific_case
|
||||
```
|
||||
|
||||
#### Continuous Integration
|
||||
|
||||
71
HISTORY.md
71
HISTORY.md
@@ -1,6 +1,75 @@
|
||||
|
||||
# Release history
|
||||
|
||||
### main branch
|
||||
|
||||
- PDF support for Sonnet and Gemini models.
|
||||
- Added `--voice-input-device` to select audio input device for voice recording, by @preynal.
|
||||
- Added `--timeout` option to configure API call timeouts.
|
||||
- Set cwd to repo root when running shell commands.
|
||||
- Added Ctrl-Up/Down keyboard shortcuts for per-message history navigation.
|
||||
- Improved error handling for failed .gitignore file operations.
|
||||
- Improved error handling for input history file permissions.
|
||||
- Improved error handling for analytics file access.
|
||||
- Removed spurious warning about disabling pretty in VSCode.
|
||||
- Removed broken support for Dart.
|
||||
- Bugfix when scraping URLs found in chat messages.
|
||||
- Better handling of __version__ import errors.
|
||||
- Improved `/drop` command to support substring matching for non-glob patterns.
|
||||
- Aider wrote 82% of the code in this release.
|
||||
|
||||
### Aider v0.65.1
|
||||
|
||||
- Bugfix to `--alias`.
|
||||
|
||||
### Aider v0.65.0
|
||||
|
||||
- Added `--alias` config to define [custom model aliases](https://aider.chat/docs/config/model-aliases.html).
|
||||
- Added `--[no-]detect-urls` flag to disable detecting and offering to scrape URLs found in the chat.
|
||||
- Ollama models now default to an 8k context window.
|
||||
- Added [RepoMap support for Dart language](https://aider.chat/docs/languages.html) by @malkoG.
|
||||
- Ask 2.5% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html).
|
||||
- Skip suggesting files that share names with files already in chat.
|
||||
- `/editor` returns and prefill the file content into the prompt, so you can use `/editor` to compose messages that start with `/commands`, etc.
|
||||
- Enhanced error handling for analytics.
|
||||
- Improved handling of UnknownEditFormat exceptions with helpful documentation links.
|
||||
- Bumped dependencies to pick up grep-ast 0.4.0 for Dart language support.
|
||||
- Aider wrote 81% of the code in this release.
|
||||
|
||||
### Aider v0.64.1
|
||||
|
||||
- Disable streaming for o1 on OpenRouter.
|
||||
|
||||
### Aider v0.64.0
|
||||
|
||||
- Added [`/editor` command](https://aider.chat/docs/usage/commands.html) to open system editor for writing prompts, by @thehunmonkgroup.
|
||||
- Full support for `gpt-4o-2024-11-20`.
|
||||
- Stream o1 models by default.
|
||||
- `/run` and suggested shell commands are less mysterious and now confirm that they "Added XX lines of output to the chat."
|
||||
- Ask 1% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html).
|
||||
- Added support for [optional multiline input tags](https://aider.chat/docs/usage/commands.html#entering-multi-line-chat-messages) with matching closing tags.
|
||||
- Improved [model settings configuration](https://aider.chat/docs/config/adv-model-settings.html#global-extra-params) with support for global `extra_params` for `litellm.completion()`.
|
||||
- Architect mode now asks to add files suggested by the LLM.
|
||||
- Fixed bug in fuzzy model name matching.
|
||||
- Added Timeout exception to handle API provider timeouts.
|
||||
- Added `--show-release-notes` to control release notes display on first run of new version.
|
||||
- Save empty dict to cache file on model metadata download failure, to delay retry.
|
||||
- Improved error handling and code formatting.
|
||||
- Aider wrote 74% of the code in this release.
|
||||
|
||||
### Aider v0.63.2
|
||||
|
||||
- Fixed bug in fuzzy model name matching when litellm provider info is missing.
|
||||
- Modified model metadata file loading to allow override of resource file.
|
||||
- Allow recursive loading of dirs using `--read`.
|
||||
- Updated dependency versions to pick up litellm fix for ollama models.
|
||||
- Added exponential backoff retry when writing files to handle editor file locks.
|
||||
- Updated Qwen 2.5 Coder 32B model configuration.
|
||||
|
||||
### Aider v0.63.1
|
||||
|
||||
- Fixed bug in git ignored file handling.
|
||||
- Improved error handling for git operations.
|
||||
|
||||
### Aider v0.63.0
|
||||
|
||||
- Support for Qwen 2.5 Coder 32B.
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
from packaging import version
|
||||
|
||||
__version__ = "0.66.1.dev"
|
||||
safe_version = __version__
|
||||
|
||||
try:
|
||||
from aider.__version__ import __version__
|
||||
from aider._version import __version__
|
||||
except Exception:
|
||||
__version__ = "0.63.1.dev"
|
||||
__version__ = safe_version + "+import"
|
||||
|
||||
if type(__version__) is not str:
|
||||
__version__ = safe_version + "+type"
|
||||
else:
|
||||
try:
|
||||
if version.parse(__version__) < version.parse(safe_version):
|
||||
__version__ = safe_version + "+less"
|
||||
except Exception:
|
||||
__version__ = safe_version + "+parse"
|
||||
|
||||
__all__ = [__version__]
|
||||
|
||||
@@ -5,7 +5,7 @@ import time
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
|
||||
from mixpanel import Mixpanel
|
||||
from mixpanel import Mixpanel, MixpanelException
|
||||
from posthog import Posthog
|
||||
|
||||
from aider import __version__
|
||||
@@ -62,13 +62,57 @@ class Analytics:
|
||||
self.permanently_disable = True
|
||||
self.save_data()
|
||||
|
||||
def need_to_ask(self):
|
||||
return not self.asked_opt_in and not self.permanently_disable
|
||||
def need_to_ask(self, args_analytics):
|
||||
if args_analytics is False:
|
||||
return False
|
||||
|
||||
could_ask = not self.asked_opt_in and not self.permanently_disable
|
||||
if not could_ask:
|
||||
return False
|
||||
|
||||
if args_analytics is True:
|
||||
return True
|
||||
|
||||
assert args_analytics is None, args_analytics
|
||||
|
||||
if not self.user_id:
|
||||
return False
|
||||
|
||||
PERCENT = 2.5
|
||||
return self.is_uuid_in_percentage(self.user_id, PERCENT)
|
||||
|
||||
def is_uuid_in_percentage(self, uuid_str, percent):
|
||||
"""Check if a UUID string falls within the first X percent of the UUID space.
|
||||
|
||||
Args:
|
||||
uuid_str: UUID string to test
|
||||
percent: Percentage threshold (0-100)
|
||||
|
||||
Returns:
|
||||
bool: True if UUID falls within the first X percent
|
||||
"""
|
||||
if not (0 <= percent <= 100):
|
||||
raise ValueError("Percentage must be between 0 and 100")
|
||||
|
||||
if not uuid_str:
|
||||
return False
|
||||
|
||||
# Convert percentage to hex threshold (1% = "04...", 10% = "1a...", etc)
|
||||
# Using first 6 hex digits
|
||||
if percent == 0:
|
||||
return False
|
||||
threshold = format(int(0xFFFFFF * percent / 100), "06x")
|
||||
return uuid_str[:6] <= threshold
|
||||
|
||||
def get_data_file_path(self):
|
||||
data_file = Path.home() / ".aider" / "analytics.json"
|
||||
data_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
return data_file
|
||||
try:
|
||||
data_file = Path.home() / ".aider" / "analytics.json"
|
||||
data_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
return data_file
|
||||
except OSError:
|
||||
# If we can't create/access the directory, just disable analytics
|
||||
self.disable(permanently=False)
|
||||
return None
|
||||
|
||||
def get_or_create_uuid(self):
|
||||
self.load_data()
|
||||
@@ -80,6 +124,9 @@ class Analytics:
|
||||
|
||||
def load_data(self):
|
||||
data_file = self.get_data_file_path()
|
||||
if not data_file:
|
||||
return
|
||||
|
||||
if data_file.exists():
|
||||
try:
|
||||
data = json.loads(data_file.read_text())
|
||||
@@ -91,14 +138,20 @@ class Analytics:
|
||||
|
||||
def save_data(self):
|
||||
data_file = self.get_data_file_path()
|
||||
if not data_file:
|
||||
return
|
||||
|
||||
data = dict(
|
||||
uuid=self.user_id,
|
||||
permanently_disable=self.permanently_disable,
|
||||
asked_opt_in=self.asked_opt_in,
|
||||
)
|
||||
|
||||
# Allow exceptions; crash if we can't record permanently_disabled=True, etc
|
||||
data_file.write_text(json.dumps(data, indent=4))
|
||||
try:
|
||||
data_file.write_text(json.dumps(data, indent=4))
|
||||
except OSError:
|
||||
# If we can't write the file, just disable analytics
|
||||
self.disable(permanently=False)
|
||||
|
||||
def get_system_info(self):
|
||||
return {
|
||||
@@ -120,7 +173,7 @@ class Analytics:
|
||||
return None
|
||||
|
||||
def event(self, event_name, main_model=None, **kwargs):
|
||||
if not (self.mp or self.ph) and not self.logfile:
|
||||
if not self.mp and not self.ph and not self.logfile:
|
||||
return
|
||||
|
||||
properties = {}
|
||||
@@ -143,7 +196,10 @@ class Analytics:
|
||||
properties["aider_version"] = __version__
|
||||
|
||||
if self.mp:
|
||||
self.mp.track(self.user_id, event_name, dict(properties))
|
||||
try:
|
||||
self.mp.track(self.user_id, event_name, dict(properties))
|
||||
except MixpanelException:
|
||||
self.mp = None # Disable mixpanel on connection errors
|
||||
|
||||
if self.ph:
|
||||
self.ph.capture(self.user_id, event_name, dict(properties))
|
||||
@@ -158,7 +214,3 @@ class Analytics:
|
||||
with open(self.logfile, "a") as f:
|
||||
json.dump(log_entry, f)
|
||||
f.write("\n")
|
||||
|
||||
def __del__(self):
|
||||
if self.ph:
|
||||
self.ph.shutdown()
|
||||
|
||||
@@ -193,12 +193,24 @@ def get_parser(default_config_files, git_root):
|
||||
default=".aider.model.metadata.json",
|
||||
help="Specify a file with context window and costs for unknown models",
|
||||
)
|
||||
group.add_argument(
|
||||
"--alias",
|
||||
action="append",
|
||||
metavar="ALIAS:MODEL",
|
||||
help="Add a model alias (can be used multiple times)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--verify-ssl",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
default=True,
|
||||
help="Verify the SSL cert when connecting to models (default: True)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--timeout",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Timeout in seconds for API calls (default: None)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--edit-format",
|
||||
"--chat-mode",
|
||||
@@ -553,7 +565,7 @@ def get_parser(default_config_files, git_root):
|
||||
group.add_argument(
|
||||
"--test",
|
||||
action="store_true",
|
||||
help="Run tests and fix problems found",
|
||||
help="Run tests, fix problems found and then exit",
|
||||
default=False,
|
||||
)
|
||||
|
||||
@@ -562,8 +574,8 @@ def get_parser(default_config_files, git_root):
|
||||
group.add_argument(
|
||||
"--analytics",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
default=False,
|
||||
help="Enable/disable analytics for one session (default: False)",
|
||||
default=None,
|
||||
help="Enable/disable analytics for current session (default: random)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--analytics-log",
|
||||
@@ -620,6 +632,12 @@ def get_parser(default_config_files, git_root):
|
||||
help="Check for new aider versions on launch",
|
||||
default=True,
|
||||
)
|
||||
group.add_argument(
|
||||
"--show-release-notes",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help="Show release notes on first run of new version (default: None, ask user)",
|
||||
default=None,
|
||||
)
|
||||
group.add_argument(
|
||||
"--install-main-branch",
|
||||
action="store_true",
|
||||
@@ -732,6 +750,16 @@ def get_parser(default_config_files, git_root):
|
||||
default=True,
|
||||
help="Enable/disable fancy input with history and completion (default: True)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--detect-urls",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
default=True,
|
||||
help="Enable/disable detection and offering to add URLs to chat (default: True)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--editor",
|
||||
help="Specify which editor to use for the /editor command",
|
||||
)
|
||||
|
||||
##########
|
||||
group = parser.add_argument_group("Voice Settings")
|
||||
@@ -748,6 +776,12 @@ def get_parser(default_config_files, git_root):
|
||||
default="en",
|
||||
help="Specify the language for voice using ISO 639-1 code (default: auto)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--voice-input-device",
|
||||
metavar="VOICE_INPUT_DEVICE",
|
||||
default=None,
|
||||
help="Specify the input device name for voice recording",
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
@@ -37,6 +37,15 @@ from ..dump import dump # noqa: F401
|
||||
from .chat_chunks import ChatChunks
|
||||
|
||||
|
||||
class UnknownEditFormat(ValueError):
|
||||
def __init__(self, edit_format, valid_formats):
|
||||
self.edit_format = edit_format
|
||||
self.valid_formats = valid_formats
|
||||
super().__init__(
|
||||
f"Unknown edit format {edit_format}. Valid formats are: {', '.join(valid_formats)}"
|
||||
)
|
||||
|
||||
|
||||
class MissingAPIKeyError(ValueError):
|
||||
pass
|
||||
|
||||
@@ -91,6 +100,7 @@ class Coder:
|
||||
cache_warming_thread = None
|
||||
num_cache_warming_pings = 0
|
||||
suggest_shell_commands = True
|
||||
detect_urls = True
|
||||
ignore_mentions = None
|
||||
chat_language = None
|
||||
|
||||
@@ -156,7 +166,12 @@ class Coder:
|
||||
res.original_kwargs = dict(kwargs)
|
||||
return res
|
||||
|
||||
raise ValueError(f"Unknown edit format {edit_format}")
|
||||
valid_formats = [
|
||||
str(c.edit_format)
|
||||
for c in coders.__all__
|
||||
if hasattr(c, "edit_format") and c.edit_format is not None
|
||||
]
|
||||
raise UnknownEditFormat(edit_format, valid_formats)
|
||||
|
||||
def clone(self, **kwargs):
|
||||
new_coder = Coder.create(from_coder=self, **kwargs)
|
||||
@@ -267,6 +282,7 @@ class Coder:
|
||||
num_cache_warming_pings=0,
|
||||
suggest_shell_commands=True,
|
||||
chat_language=None,
|
||||
detect_urls=True,
|
||||
):
|
||||
# Fill in a dummy Analytics if needed, but it is never .enable()'d
|
||||
self.analytics = analytics if analytics is not None else Analytics()
|
||||
@@ -280,6 +296,7 @@ class Coder:
|
||||
self.ignore_mentions = set()
|
||||
|
||||
self.suggest_shell_commands = suggest_shell_commands
|
||||
self.detect_urls = detect_urls
|
||||
|
||||
self.num_cache_warming_pings = num_cache_warming_pings
|
||||
|
||||
@@ -648,6 +665,8 @@ class Coder:
|
||||
|
||||
def get_readonly_files_messages(self):
|
||||
readonly_messages = []
|
||||
|
||||
# Handle non-image files
|
||||
read_only_content = self.get_read_only_files_content()
|
||||
if read_only_content:
|
||||
readonly_messages += [
|
||||
@@ -659,6 +678,15 @@ class Coder:
|
||||
content="Ok, I will use these files as references.",
|
||||
),
|
||||
]
|
||||
|
||||
# Handle image files
|
||||
images_message = self.get_images_message(self.abs_read_only_fnames)
|
||||
if images_message is not None:
|
||||
readonly_messages += [
|
||||
images_message,
|
||||
dict(role="assistant", content="Ok, I will use these images as references."),
|
||||
]
|
||||
|
||||
return readonly_messages
|
||||
|
||||
def get_chat_files_messages(self):
|
||||
@@ -680,7 +708,7 @@ class Coder:
|
||||
dict(role="assistant", content=files_reply),
|
||||
]
|
||||
|
||||
images_message = self.get_images_message()
|
||||
images_message = self.get_images_message(self.abs_fnames)
|
||||
if images_message is not None:
|
||||
chat_files_messages += [
|
||||
images_message,
|
||||
@@ -689,23 +717,42 @@ class Coder:
|
||||
|
||||
return chat_files_messages
|
||||
|
||||
def get_images_message(self):
|
||||
if not self.main_model.info.get("supports_vision"):
|
||||
def get_images_message(self, fnames):
|
||||
supports_images = self.main_model.info.get("supports_vision")
|
||||
supports_pdfs = self.main_model.info.get("supports_pdf_input") or self.main_model.info.get(
|
||||
"max_pdf_size_mb"
|
||||
)
|
||||
|
||||
# https://github.com/BerriAI/litellm/pull/6928
|
||||
supports_pdfs = supports_pdfs or "claude-3-5-sonnet-20241022" in self.main_model.name
|
||||
|
||||
if not (supports_images or supports_pdfs):
|
||||
return None
|
||||
|
||||
image_messages = []
|
||||
for fname, content in self.get_abs_fnames_content():
|
||||
if is_image_file(fname):
|
||||
with open(fname, "rb") as image_file:
|
||||
encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
|
||||
mime_type, _ = mimetypes.guess_type(fname)
|
||||
if mime_type and mime_type.startswith("image/"):
|
||||
image_url = f"data:{mime_type};base64,{encoded_string}"
|
||||
rel_fname = self.get_rel_fname(fname)
|
||||
image_messages += [
|
||||
{"type": "text", "text": f"Image file: {rel_fname}"},
|
||||
{"type": "image_url", "image_url": {"url": image_url, "detail": "high"}},
|
||||
]
|
||||
for fname in fnames:
|
||||
if not is_image_file(fname):
|
||||
continue
|
||||
|
||||
mime_type, _ = mimetypes.guess_type(fname)
|
||||
if not mime_type:
|
||||
continue
|
||||
|
||||
with open(fname, "rb") as image_file:
|
||||
encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
|
||||
image_url = f"data:{mime_type};base64,{encoded_string}"
|
||||
rel_fname = self.get_rel_fname(fname)
|
||||
|
||||
if mime_type.startswith("image/") and supports_images:
|
||||
image_messages += [
|
||||
{"type": "text", "text": f"Image file: {rel_fname}"},
|
||||
{"type": "image_url", "image_url": {"url": image_url, "detail": "high"}},
|
||||
]
|
||||
elif mime_type == "application/pdf" and supports_pdfs:
|
||||
image_messages += [
|
||||
{"type": "text", "text": f"PDF file: {rel_fname}"},
|
||||
{"type": "image_url", "image_url": image_url},
|
||||
]
|
||||
|
||||
if not image_messages:
|
||||
return None
|
||||
@@ -724,6 +771,7 @@ class Coder:
|
||||
self.lint_outcome = None
|
||||
self.test_outcome = None
|
||||
self.shell_commands = []
|
||||
self.message_cost = 0
|
||||
|
||||
if self.repo:
|
||||
self.commit_before_message.append(self.repo.get_head_commit_sha())
|
||||
@@ -767,7 +815,7 @@ class Coder:
|
||||
return self.commands.run(inp)
|
||||
|
||||
self.check_for_file_mentions(inp)
|
||||
self.check_for_urls(inp)
|
||||
inp = self.check_for_urls(inp)
|
||||
|
||||
return inp
|
||||
|
||||
@@ -812,9 +860,11 @@ class Coder:
|
||||
|
||||
def check_for_urls(self, inp: str) -> List[str]:
|
||||
"""Check input for URLs and offer to add them to the chat."""
|
||||
if not self.detect_urls:
|
||||
return inp
|
||||
|
||||
url_pattern = re.compile(r"(https?://[^\s/$.?#].[^\s]*[^\s,.])")
|
||||
urls = list(set(url_pattern.findall(inp))) # Use set to remove duplicates
|
||||
added_urls = []
|
||||
group = ConfirmGroup(urls)
|
||||
for url in urls:
|
||||
if url not in self.rejected_urls:
|
||||
@@ -824,11 +874,10 @@ class Coder:
|
||||
):
|
||||
inp += "\n\n"
|
||||
inp += self.commands.cmd_web(url, return_content=True)
|
||||
added_urls.append(url)
|
||||
else:
|
||||
self.rejected_urls.add(url)
|
||||
|
||||
return added_urls
|
||||
return inp
|
||||
|
||||
def keyboard_interrupt(self):
|
||||
now = time.time()
|
||||
@@ -836,6 +885,7 @@ class Coder:
|
||||
thresh = 2 # seconds
|
||||
if self.last_keyboard_interrupt and now - self.last_keyboard_interrupt < thresh:
|
||||
self.io.tool_warning("\n\n^C KeyboardInterrupt")
|
||||
self.event("exit", reason="Control-C")
|
||||
sys.exit()
|
||||
|
||||
self.io.tool_warning("\n\n^C again to exit")
|
||||
@@ -962,7 +1012,7 @@ class Coder:
|
||||
if self.chat_language:
|
||||
language = self.chat_language
|
||||
else:
|
||||
language = "in the same language they are using"
|
||||
language = "the same language they are using"
|
||||
|
||||
prompt = prompt.format(
|
||||
fence=self.fence,
|
||||
@@ -1059,7 +1109,7 @@ class Coder:
|
||||
max_input_tokens = self.main_model.info.get("max_input_tokens") or 0
|
||||
# Add the reminder prompt if we still have room to include it.
|
||||
if (
|
||||
max_input_tokens is None
|
||||
not max_input_tokens
|
||||
or total_tokens < max_input_tokens
|
||||
and self.gpt_prompts.system_reminder
|
||||
):
|
||||
@@ -1137,6 +1187,8 @@ class Coder:
|
||||
return chunks
|
||||
|
||||
def send_message(self, inp):
|
||||
self.event("message_send_starting")
|
||||
|
||||
self.cur_messages += [
|
||||
dict(role="user", content=inp),
|
||||
]
|
||||
@@ -1216,6 +1268,7 @@ class Coder:
|
||||
lines = traceback.format_exception(type(err), err, err.__traceback__)
|
||||
self.io.tool_warning("".join(lines))
|
||||
self.io.tool_error(str(err))
|
||||
self.event("message_send_exception", exception=str(err))
|
||||
return
|
||||
finally:
|
||||
if self.mdstream:
|
||||
@@ -1245,10 +1298,19 @@ class Coder:
|
||||
else:
|
||||
content = ""
|
||||
|
||||
try:
|
||||
self.reply_completed()
|
||||
except KeyboardInterrupt:
|
||||
interrupted = True
|
||||
if not interrupted:
|
||||
add_rel_files_message = self.check_for_file_mentions(content)
|
||||
if add_rel_files_message:
|
||||
if self.reflected_message:
|
||||
self.reflected_message += "\n\n" + add_rel_files_message
|
||||
else:
|
||||
self.reflected_message = add_rel_files_message
|
||||
return
|
||||
|
||||
try:
|
||||
self.reply_completed()
|
||||
except KeyboardInterrupt:
|
||||
interrupted = True
|
||||
|
||||
if interrupted:
|
||||
content += "\n^C KeyboardInterrupt"
|
||||
@@ -1299,13 +1361,6 @@ class Coder:
|
||||
self.update_cur_messages()
|
||||
return
|
||||
|
||||
add_rel_files_message = self.check_for_file_mentions(content)
|
||||
if add_rel_files_message:
|
||||
if self.reflected_message:
|
||||
self.reflected_message += "\n\n" + add_rel_files_message
|
||||
else:
|
||||
self.reflected_message = add_rel_files_message
|
||||
|
||||
def reply_completed(self):
|
||||
pass
|
||||
|
||||
@@ -1348,9 +1403,7 @@ class Coder:
|
||||
res.append("- Ask for smaller changes in each request.")
|
||||
res.append("- Break your code into smaller source files.")
|
||||
if "diff" not in self.main_model.edit_format:
|
||||
res.append(
|
||||
"- Use a stronger model like gpt-4o, sonnet or opus that can return diffs."
|
||||
)
|
||||
res.append("- Use a stronger model that can return diffs.")
|
||||
|
||||
if input_tokens >= max_input_tokens or total_tokens >= max_input_tokens:
|
||||
res.append("")
|
||||
@@ -1403,9 +1456,18 @@ class Coder:
|
||||
|
||||
addable_rel_fnames = self.get_addable_relative_files()
|
||||
|
||||
# Get basenames of files already in chat or read-only
|
||||
existing_basenames = {os.path.basename(f) for f in self.get_inchat_relative_files()} | {
|
||||
os.path.basename(self.get_rel_fname(f)) for f in self.abs_read_only_fnames
|
||||
}
|
||||
|
||||
mentioned_rel_fnames = set()
|
||||
fname_to_rel_fnames = {}
|
||||
for rel_fname in addable_rel_fnames:
|
||||
# Skip files that share a basename with files already in chat
|
||||
if os.path.basename(rel_fname) in existing_basenames:
|
||||
continue
|
||||
|
||||
normalized_rel_fname = rel_fname.replace("\\", "/")
|
||||
normalized_words = set(word.replace("\\", "/") for word in words)
|
||||
if normalized_rel_fname in normalized_words:
|
||||
@@ -2055,13 +2117,14 @@ class Coder:
|
||||
self.io.tool_output(f"Running {command}")
|
||||
# Add the command to input history
|
||||
self.io.add_to_input_history(f"/run {command.strip()}")
|
||||
exit_status, output = run_cmd(command, error_print=self.io.tool_error)
|
||||
exit_status, output = run_cmd(command, error_print=self.io.tool_error, cwd=self.root)
|
||||
if output:
|
||||
accumulated_output += f"Output from {command}\n{output}\n"
|
||||
|
||||
if accumulated_output.strip() and not self.io.confirm_ask(
|
||||
if accumulated_output.strip() and self.io.confirm_ask(
|
||||
"Add command output to the chat?", allow_never=True
|
||||
):
|
||||
accumulated_output = ""
|
||||
|
||||
return accumulated_output
|
||||
num_lines = len(accumulated_output.strip().splitlines())
|
||||
line_plural = "line" if num_lines == 1 else "lines"
|
||||
self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.")
|
||||
return accumulated_output
|
||||
|
||||
@@ -14,6 +14,7 @@ from prompt_toolkit.completion import Completion, PathCompleter
|
||||
from prompt_toolkit.document import Document
|
||||
|
||||
from aider import models, prompts, voice
|
||||
from aider.editor import pipe_editor
|
||||
from aider.format_settings import format_settings
|
||||
from aider.help import Help, install_help_extra
|
||||
from aider.llm import litellm
|
||||
@@ -45,7 +46,15 @@ class Commands:
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self, io, coder, voice_language=None, verify_ssl=True, args=None, parser=None, verbose=False
|
||||
self,
|
||||
io,
|
||||
coder,
|
||||
voice_language=None,
|
||||
verify_ssl=True,
|
||||
args=None,
|
||||
parser=None,
|
||||
verbose=False,
|
||||
editor=None,
|
||||
):
|
||||
self.io = io
|
||||
self.coder = coder
|
||||
@@ -60,6 +69,7 @@ class Commands:
|
||||
self.voice_language = voice_language
|
||||
|
||||
self.help = None
|
||||
self.editor = editor
|
||||
|
||||
def cmd_model(self, args):
|
||||
"Switch to a new LLM"
|
||||
@@ -798,15 +808,33 @@ class Commands:
|
||||
# Expand tilde in the path
|
||||
expanded_word = os.path.expanduser(word)
|
||||
|
||||
# Handle read-only files separately, without glob_filtered_to_repo
|
||||
read_only_matched = [f for f in self.coder.abs_read_only_fnames if expanded_word in f]
|
||||
# Handle read-only files with substring matching and samefile check
|
||||
read_only_matched = []
|
||||
for f in self.coder.abs_read_only_fnames:
|
||||
if expanded_word in f:
|
||||
read_only_matched.append(f)
|
||||
continue
|
||||
|
||||
if read_only_matched:
|
||||
for matched_file in read_only_matched:
|
||||
self.coder.abs_read_only_fnames.remove(matched_file)
|
||||
self.io.tool_output(f"Removed read-only file {matched_file} from the chat")
|
||||
# Try samefile comparison for relative paths
|
||||
try:
|
||||
abs_word = os.path.abspath(expanded_word)
|
||||
if os.path.samefile(abs_word, f):
|
||||
read_only_matched.append(f)
|
||||
except (FileNotFoundError, OSError):
|
||||
continue
|
||||
|
||||
matched_files = self.glob_filtered_to_repo(expanded_word)
|
||||
for matched_file in read_only_matched:
|
||||
self.coder.abs_read_only_fnames.remove(matched_file)
|
||||
self.io.tool_output(f"Removed read-only file {matched_file} from the chat")
|
||||
|
||||
# For editable files, use glob if word contains glob chars, otherwise use substring
|
||||
if any(c in expanded_word for c in "*?[]"):
|
||||
matched_files = self.glob_filtered_to_repo(expanded_word)
|
||||
else:
|
||||
# Use substring matching like we do for read-only files
|
||||
matched_files = [
|
||||
self.coder.get_rel_fname(f) for f in self.coder.abs_fnames if expanded_word in f
|
||||
]
|
||||
|
||||
if not matched_files:
|
||||
matched_files.append(expanded_word)
|
||||
@@ -866,9 +894,8 @@ class Commands:
|
||||
def cmd_run(self, args, add_on_nonzero_exit=False):
|
||||
"Run a shell command and optionally add the output to the chat (alias: !)"
|
||||
exit_status, combined_output = run_cmd(
|
||||
args, verbose=self.verbose, error_print=self.io.tool_error
|
||||
args, verbose=self.verbose, error_print=self.io.tool_error, cwd=self.coder.root
|
||||
)
|
||||
instructions = None
|
||||
|
||||
if combined_output is None:
|
||||
return
|
||||
@@ -876,44 +903,31 @@ class Commands:
|
||||
if add_on_nonzero_exit:
|
||||
add = exit_status != 0
|
||||
else:
|
||||
self.io.tool_output()
|
||||
response = self.io.prompt_ask(
|
||||
"Add the output to the chat?\n(Y)es/(n)o/message with instructions:",
|
||||
).strip()
|
||||
self.io.tool_output()
|
||||
|
||||
if response.lower() in ["yes", "y"]:
|
||||
add = True
|
||||
elif response.lower() in ["no", "n"]:
|
||||
add = False
|
||||
else:
|
||||
add = True
|
||||
instructions = response
|
||||
if response.strip():
|
||||
self.io.user_input(response, log_only=True)
|
||||
self.io.add_to_input_history(response)
|
||||
add = self.io.confirm_ask("Add command output to the chat?")
|
||||
|
||||
if add:
|
||||
for line in combined_output.splitlines():
|
||||
self.io.tool_output(line, log_only=True)
|
||||
num_lines = len(combined_output.strip().splitlines())
|
||||
line_plural = "line" if num_lines == 1 else "lines"
|
||||
self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.")
|
||||
|
||||
msg = prompts.run_output.format(
|
||||
command=args,
|
||||
output=combined_output,
|
||||
)
|
||||
|
||||
if instructions:
|
||||
msg = instructions + "\n\n" + msg
|
||||
|
||||
return msg
|
||||
self.coder.cur_messages += [
|
||||
dict(role="user", content=msg),
|
||||
dict(role="assistant", content="Ok."),
|
||||
]
|
||||
|
||||
def cmd_exit(self, args):
|
||||
"Exit the application"
|
||||
self.coder.event("exit", reason="/exit")
|
||||
sys.exit()
|
||||
|
||||
def cmd_quit(self, args):
|
||||
"Exit the application"
|
||||
sys.exit()
|
||||
self.cmd_exit(args)
|
||||
|
||||
def cmd_ls(self, args):
|
||||
"List all known files and indicate which are included in the chat session"
|
||||
@@ -1085,7 +1099,9 @@ class Commands:
|
||||
self.io.tool_error("To use /voice you must provide an OpenAI API key.")
|
||||
return
|
||||
try:
|
||||
self.voice = voice.Voice(audio_format=self.args.voice_format)
|
||||
self.voice = voice.Voice(
|
||||
audio_format=self.args.voice_format, device_name=self.args.voice_input_device
|
||||
)
|
||||
except voice.SoundDeviceError:
|
||||
self.io.tool_error(
|
||||
"Unable to import `sounddevice` and/or `soundfile`, is portaudio installed?"
|
||||
@@ -1366,6 +1382,13 @@ class Commands:
|
||||
|
||||
report_github_issue(issue_text, title=title, confirm=False)
|
||||
|
||||
def cmd_editor(self, initial_content=""):
|
||||
"Open an editor to write a prompt"
|
||||
|
||||
user_input = pipe_editor(initial_content, suffix="md", editor=self.editor)
|
||||
if user_input.strip():
|
||||
self.io.set_placeholder(user_input.rstrip())
|
||||
|
||||
|
||||
def expand_subdir(file_path):
|
||||
if file_path.is_file():
|
||||
|
||||
@@ -50,7 +50,6 @@ def diff_partial_update(lines_orig, lines_updated, final=False, fname=None):
|
||||
# dump(lines_orig)
|
||||
# dump(lines_updated)
|
||||
|
||||
assert_newlines(lines_orig)
|
||||
assert_newlines(lines_orig)
|
||||
|
||||
num_orig_lines = len(lines_orig)
|
||||
|
||||
146
aider/editor.py
Normal file
146
aider/editor.py
Normal file
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
Editor module for handling system text editor interactions.
|
||||
|
||||
This module provides functionality to:
|
||||
- Discover and launch the system's configured text editor
|
||||
- Create and manage temporary files for editing
|
||||
- Handle editor preferences from environment variables
|
||||
- Support cross-platform editor operations
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import shlex
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from rich.console import Console
|
||||
|
||||
DEFAULT_EDITOR_NIX = "vi"
|
||||
DEFAULT_EDITOR_OS_X = "vim"
|
||||
DEFAULT_EDITOR_WINDOWS = "notepad"
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
def print_status_message(success, message, style=None):
|
||||
"""
|
||||
Print a status message with appropriate styling.
|
||||
|
||||
:param success: Whether the operation was successful
|
||||
:param message: The message to display
|
||||
:param style: Optional style override. If None, uses green for success and red for failure
|
||||
"""
|
||||
if style is None:
|
||||
style = "bold green" if success else "bold red"
|
||||
console.print(message, style=style)
|
||||
print("")
|
||||
|
||||
|
||||
def write_temp_file(
|
||||
input_data="",
|
||||
suffix=None,
|
||||
prefix=None,
|
||||
dir=None,
|
||||
):
|
||||
"""
|
||||
Create a temporary file with the given input data.
|
||||
|
||||
:param input_data: Content to write to the temporary file
|
||||
:param suffix: Optional file extension (without the dot)
|
||||
:param prefix: Optional prefix for the temporary filename
|
||||
:param dir: Optional directory to create the file in
|
||||
:return: Path to the created temporary file
|
||||
:raises: OSError if file creation or writing fails
|
||||
"""
|
||||
kwargs = {"prefix": prefix, "dir": dir}
|
||||
if suffix:
|
||||
kwargs["suffix"] = f".{suffix}"
|
||||
fd, filepath = tempfile.mkstemp(**kwargs)
|
||||
try:
|
||||
with os.fdopen(fd, "w") as f:
|
||||
f.write(input_data)
|
||||
except Exception:
|
||||
os.close(fd)
|
||||
raise
|
||||
return filepath
|
||||
|
||||
|
||||
def get_environment_editor(default=None):
|
||||
"""
|
||||
Fetches the preferred editor from the environment variables.
|
||||
|
||||
This function checks the following environment variables in order to
|
||||
determine the user's preferred editor:
|
||||
|
||||
- VISUAL
|
||||
- EDITOR
|
||||
|
||||
:param default: The default editor to return if no environment variable is set.
|
||||
:type default: str or None
|
||||
:return: The preferred editor as specified by environment variables or the default value.
|
||||
:rtype: str or None
|
||||
"""
|
||||
editor = os.environ.get("VISUAL", os.environ.get("EDITOR", default))
|
||||
return editor
|
||||
|
||||
|
||||
def discover_editor(editor_override=None):
|
||||
"""
|
||||
Discovers and returns the appropriate editor command as a list of arguments.
|
||||
|
||||
Handles cases where the editor command includes arguments, including quoted arguments
|
||||
with spaces (e.g. 'vim -c "set noswapfile"').
|
||||
|
||||
:return: A list of command parts ready for subprocess execution
|
||||
:rtype: list[str]
|
||||
"""
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
default_editor = DEFAULT_EDITOR_WINDOWS
|
||||
elif system == "Darwin":
|
||||
default_editor = DEFAULT_EDITOR_OS_X
|
||||
else:
|
||||
default_editor = DEFAULT_EDITOR_NIX
|
||||
if editor_override:
|
||||
editor = editor_override
|
||||
else:
|
||||
editor = get_environment_editor(default_editor)
|
||||
try:
|
||||
return shlex.split(editor)
|
||||
except ValueError as e:
|
||||
raise RuntimeError(f"Invalid editor command format '{editor}': {e}")
|
||||
|
||||
|
||||
def pipe_editor(input_data="", suffix=None, editor=None):
|
||||
"""
|
||||
Opens the system editor with optional input data and returns the edited content.
|
||||
|
||||
This function creates a temporary file with the provided input data, opens it in
|
||||
the system editor, waits for the user to make changes and close the editor, then
|
||||
reads and returns the modified content. The temporary file is deleted afterwards.
|
||||
|
||||
:param input_data: Initial content to populate the editor with
|
||||
:type input_data: str
|
||||
:param suffix: Optional file extension for the temporary file (e.g. '.txt', '.md')
|
||||
:type suffix: str or None
|
||||
:return: The edited content after the editor is closed
|
||||
:rtype: str
|
||||
"""
|
||||
filepath = write_temp_file(input_data, suffix)
|
||||
command_parts = discover_editor(editor)
|
||||
command_parts.append(filepath)
|
||||
subprocess.call(command_parts)
|
||||
with open(filepath, "r") as f:
|
||||
output_data = f.read()
|
||||
try:
|
||||
os.remove(filepath)
|
||||
except PermissionError:
|
||||
print_status_message(
|
||||
False,
|
||||
(
|
||||
f"WARNING: Unable to delete temporary file {filepath!r}. You may need to delete it"
|
||||
" manually."
|
||||
),
|
||||
)
|
||||
return output_data
|
||||
@@ -40,6 +40,11 @@ EXCEPTIONS = [
|
||||
ExInfo("ServiceUnavailableError", True, "The API provider's servers are down or overloaded."),
|
||||
ExInfo("UnprocessableEntityError", True, None),
|
||||
ExInfo("UnsupportedParamsError", True, None),
|
||||
ExInfo(
|
||||
"Timeout",
|
||||
True,
|
||||
"The API provider timed out without returning a response. They may be down or overloaded.",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -7,4 +7,5 @@ exclude_website_pats = [
|
||||
"docs/unified-diffs.md",
|
||||
"docs/leaderboards/index.md",
|
||||
"assets/**",
|
||||
"**/.DS_Store",
|
||||
]
|
||||
|
||||
122
aider/io.py
122
aider/io.py
@@ -1,5 +1,6 @@
|
||||
import base64
|
||||
import os
|
||||
import time
|
||||
import webbrowser
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
@@ -197,6 +198,7 @@ class InputOutput:
|
||||
editingmode=EditingMode.EMACS,
|
||||
fancy_input=True,
|
||||
):
|
||||
self.placeholder = None
|
||||
self.never_prompts = set()
|
||||
self.editingmode = editingmode
|
||||
no_color = os.environ.get("NO_COLOR")
|
||||
@@ -333,14 +335,36 @@ class InputOutput:
|
||||
self.tool_error("Use --encoding to set the unicode encoding.")
|
||||
return
|
||||
|
||||
def write_text(self, filename, content):
|
||||
def write_text(self, filename, content, max_retries=5, initial_delay=0.1):
|
||||
"""
|
||||
Writes content to a file, retrying with progressive backoff if the file is locked.
|
||||
|
||||
:param filename: Path to the file to write.
|
||||
:param content: Content to write to the file.
|
||||
:param max_retries: Maximum number of retries if a file lock is encountered.
|
||||
:param initial_delay: Initial delay (in seconds) before the first retry.
|
||||
"""
|
||||
if self.dry_run:
|
||||
return
|
||||
try:
|
||||
with open(str(filename), "w", encoding=self.encoding) as f:
|
||||
f.write(content)
|
||||
except OSError as err:
|
||||
self.tool_error(f"Unable to write file {filename}: {err}")
|
||||
|
||||
delay = initial_delay
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
with open(str(filename), "w", encoding=self.encoding) as f:
|
||||
f.write(content)
|
||||
return # Successfully wrote the file
|
||||
except PermissionError as err:
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(delay)
|
||||
delay *= 2 # Exponential backoff
|
||||
else:
|
||||
self.tool_error(
|
||||
f"Unable to write file {filename} after {max_retries} attempts: {err}"
|
||||
)
|
||||
raise
|
||||
except OSError as err:
|
||||
self.tool_error(f"Unable to write file {filename}: {err}")
|
||||
raise
|
||||
|
||||
def rule(self):
|
||||
if self.pretty:
|
||||
@@ -394,6 +418,16 @@ class InputOutput:
|
||||
"Ignore Ctrl when pressing space bar"
|
||||
event.current_buffer.insert_text(" ")
|
||||
|
||||
@kb.add("c-up")
|
||||
def _(event):
|
||||
"Navigate backward through history"
|
||||
event.current_buffer.history_backward()
|
||||
|
||||
@kb.add("c-down")
|
||||
def _(event):
|
||||
"Navigate forward through history"
|
||||
event.current_buffer.history_forward()
|
||||
|
||||
@kb.add("escape", "c-m", eager=True)
|
||||
def _(event):
|
||||
event.current_buffer.insert_text("\n")
|
||||
@@ -404,8 +438,13 @@ class InputOutput:
|
||||
|
||||
try:
|
||||
if self.prompt_session:
|
||||
# Use placeholder if set, then clear it
|
||||
default = self.placeholder or ""
|
||||
self.placeholder = None
|
||||
|
||||
line = self.prompt_session.prompt(
|
||||
show,
|
||||
default=default,
|
||||
completer=completer_instance,
|
||||
reserve_space_for_menu=4,
|
||||
complete_style=CompleteStyle.MULTI_COLUMN,
|
||||
@@ -418,13 +457,38 @@ class InputOutput:
|
||||
self.tool_error(str(err))
|
||||
return ""
|
||||
|
||||
if line and line[0] == "{" and not multiline_input:
|
||||
multiline_input = True
|
||||
inp += line[1:] + "\n"
|
||||
if line.strip("\r\n") and not multiline_input:
|
||||
stripped = line.strip("\r\n")
|
||||
if stripped == "{":
|
||||
multiline_input = True
|
||||
multiline_tag = None
|
||||
inp += ""
|
||||
elif stripped[0] == "{":
|
||||
# Extract tag if it exists (only alphanumeric chars)
|
||||
tag = "".join(c for c in stripped[1:] if c.isalnum())
|
||||
if stripped == "{" + tag:
|
||||
multiline_input = True
|
||||
multiline_tag = tag
|
||||
inp += ""
|
||||
else:
|
||||
inp = line
|
||||
break
|
||||
else:
|
||||
inp = line
|
||||
break
|
||||
continue
|
||||
elif line and line[-1] == "}" and multiline_input:
|
||||
inp += line[:-1] + "\n"
|
||||
break
|
||||
elif multiline_input and line.strip():
|
||||
if multiline_tag:
|
||||
# Check if line is exactly "tag}"
|
||||
if line.strip("\r\n") == f"{multiline_tag}}}":
|
||||
break
|
||||
else:
|
||||
inp += line + "\n"
|
||||
# Check if line is exactly "}"
|
||||
elif line.strip("\r\n") == "}":
|
||||
break
|
||||
else:
|
||||
inp += line + "\n"
|
||||
elif multiline_input:
|
||||
inp += line + "\n"
|
||||
else:
|
||||
@@ -438,10 +502,13 @@ class InputOutput:
|
||||
def add_to_input_history(self, inp):
|
||||
if not self.input_history_file:
|
||||
return
|
||||
FileHistory(self.input_history_file).append_string(inp)
|
||||
# Also add to the in-memory history if it exists
|
||||
if hasattr(self, "session") and hasattr(self.session, "history"):
|
||||
self.session.history.append_string(inp)
|
||||
try:
|
||||
FileHistory(self.input_history_file).append_string(inp)
|
||||
# Also add to the in-memory history if it exists
|
||||
if self.prompt_session and self.prompt_session.history:
|
||||
self.prompt_session.history.append_string(inp)
|
||||
except OSError as err:
|
||||
self.tool_warning(f"Unable to write to input history file: {err}")
|
||||
|
||||
def get_input_history(self):
|
||||
if not self.input_history_file:
|
||||
@@ -458,14 +525,17 @@ class InputOutput:
|
||||
log_file.write(f"{role.upper()} {timestamp}\n")
|
||||
log_file.write(content + "\n")
|
||||
|
||||
def display_user_input(self, inp):
|
||||
if self.pretty and self.user_input_color:
|
||||
style = dict(style=self.user_input_color)
|
||||
else:
|
||||
style = dict()
|
||||
|
||||
self.console.print(Text(inp), **style)
|
||||
|
||||
def user_input(self, inp, log_only=True):
|
||||
if not log_only:
|
||||
if self.pretty and self.user_input_color:
|
||||
style = dict(style=self.user_input_color)
|
||||
else:
|
||||
style = dict()
|
||||
|
||||
self.console.print(Text(inp), **style)
|
||||
self.display_user_input(inp)
|
||||
|
||||
prefix = "####"
|
||||
if inp:
|
||||
@@ -485,11 +555,11 @@ class InputOutput:
|
||||
hist = "\n" + content.strip() + "\n\n"
|
||||
self.append_chat_history(hist)
|
||||
|
||||
def offer_url(self, url, prompt="Open URL for more info?"):
|
||||
def offer_url(self, url, prompt="Open URL for more info?", allow_never=True):
|
||||
"""Offer to open a URL in the browser, returns True if opened."""
|
||||
if url in self.never_prompts:
|
||||
return False
|
||||
if self.confirm_ask(prompt, subject=url, allow_never=True):
|
||||
if self.confirm_ask(prompt, subject=url, allow_never=allow_never):
|
||||
webbrowser.open(url)
|
||||
return True
|
||||
return False
|
||||
@@ -688,6 +758,10 @@ class InputOutput:
|
||||
|
||||
self.console.print(show_resp)
|
||||
|
||||
def set_placeholder(self, placeholder):
|
||||
"""Set a one-time placeholder text for the next input prompt."""
|
||||
self.placeholder = placeholder
|
||||
|
||||
def print(self, message=""):
|
||||
print(message)
|
||||
|
||||
|
||||
@@ -49,11 +49,11 @@ class Linter:
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
cwd=self.root,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
encoding=self.encoding,
|
||||
errors="replace",
|
||||
cwd=self.root,
|
||||
)
|
||||
except OSError as err:
|
||||
print(f"Unable to execute lint command: {err}")
|
||||
@@ -152,12 +152,12 @@ class Linter:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
flake8_cmd,
|
||||
cwd=self.root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
encoding=self.encoding,
|
||||
errors="replace",
|
||||
cwd=self.root,
|
||||
)
|
||||
errors = result.stdout + result.stderr
|
||||
except Exception as e:
|
||||
|
||||
179
aider/main.py
179
aider/main.py
@@ -5,6 +5,8 @@ import re
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import webbrowser
|
||||
from dataclasses import fields
|
||||
from pathlib import Path
|
||||
|
||||
import git
|
||||
@@ -16,11 +18,13 @@ from aider import __version__, models, urls, utils
|
||||
from aider.analytics import Analytics
|
||||
from aider.args import get_parser
|
||||
from aider.coders import Coder
|
||||
from aider.coders.base_coder import UnknownEditFormat
|
||||
from aider.commands import Commands, SwitchCoder
|
||||
from aider.format_settings import format_settings, scrub_sensitive_info
|
||||
from aider.history import ChatSummary
|
||||
from aider.io import InputOutput
|
||||
from aider.llm import litellm # noqa: F401; properly init litellm on launch
|
||||
from aider.models import ModelSettings
|
||||
from aider.repo import ANY_GIT_ERROR, GitRepo
|
||||
from aider.report import report_uncaught_exceptions
|
||||
from aider.versioncheck import check_version, install_from_main_branch, install_upgrade
|
||||
@@ -153,13 +157,17 @@ def check_gitignore(git_root, io, ask=True):
|
||||
|
||||
gitignore_file = Path(git_root) / ".gitignore"
|
||||
if gitignore_file.exists():
|
||||
content = io.read_text(gitignore_file)
|
||||
if content is None:
|
||||
try:
|
||||
content = io.read_text(gitignore_file)
|
||||
if content is None:
|
||||
return
|
||||
existing_lines = content.splitlines()
|
||||
for pat in patterns:
|
||||
if pat not in existing_lines:
|
||||
patterns_to_add.append(pat)
|
||||
except OSError as e:
|
||||
io.tool_error(f"Error when trying to read {gitignore_file}: {e}")
|
||||
return
|
||||
existing_lines = content.splitlines()
|
||||
for pat in patterns:
|
||||
if pat not in existing_lines:
|
||||
patterns_to_add.append(pat)
|
||||
else:
|
||||
content = ""
|
||||
patterns_to_add = patterns
|
||||
@@ -173,9 +181,17 @@ def check_gitignore(git_root, io, ask=True):
|
||||
if content and not content.endswith("\n"):
|
||||
content += "\n"
|
||||
content += "\n".join(patterns_to_add) + "\n"
|
||||
io.write_text(gitignore_file, content)
|
||||
|
||||
io.tool_output(f"Added {', '.join(patterns_to_add)} to .gitignore")
|
||||
try:
|
||||
io.write_text(gitignore_file, content)
|
||||
io.tool_output(f"Added {', '.join(patterns_to_add)} to .gitignore")
|
||||
except OSError as e:
|
||||
io.tool_error(f"Error when trying to write to {gitignore_file}: {e}")
|
||||
io.tool_output(
|
||||
"Try running with appropriate permissions or manually add these patterns to .gitignore:"
|
||||
)
|
||||
for pattern in patterns_to_add:
|
||||
io.tool_output(f" {pattern}")
|
||||
|
||||
|
||||
def check_streamlit_install(io):
|
||||
@@ -332,14 +348,16 @@ def load_dotenv_files(git_root, dotenv_fname, encoding="utf-8"):
|
||||
|
||||
|
||||
def register_litellm_models(git_root, model_metadata_fname, io, verbose=False):
|
||||
model_metatdata_files = generate_search_path_list(
|
||||
".aider.model.metadata.json", git_root, model_metadata_fname
|
||||
)
|
||||
model_metatdata_files = []
|
||||
|
||||
# Add the resource file path
|
||||
resource_metadata = importlib_resources.files("aider.resources").joinpath("model-metadata.json")
|
||||
model_metatdata_files.append(str(resource_metadata))
|
||||
|
||||
model_metatdata_files += generate_search_path_list(
|
||||
".aider.model.metadata.json", git_root, model_metadata_fname
|
||||
)
|
||||
|
||||
try:
|
||||
model_metadata_files_loaded = models.register_litellm_models(model_metatdata_files)
|
||||
if len(model_metadata_files_loaded) > 0 and verbose:
|
||||
@@ -449,6 +467,10 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
litellm._lazy_module.client_session = httpx.Client(verify=False)
|
||||
litellm._lazy_module.aclient_session = httpx.AsyncClient(verify=False)
|
||||
|
||||
if args.timeout:
|
||||
litellm._load_litellm()
|
||||
litellm._lazy_module.request_timeout = args.timeout
|
||||
|
||||
if args.dark_mode:
|
||||
args.user_input_color = "#32FF32"
|
||||
args.tool_error_color = "#FF3333"
|
||||
@@ -503,8 +525,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
io.tool_warning("Terminal does not support pretty output (UnicodeDecodeError)")
|
||||
|
||||
analytics = Analytics(logfile=args.analytics_log, permanently_disable=args.analytics_disable)
|
||||
if args.analytics:
|
||||
if analytics.need_to_ask():
|
||||
if args.analytics is not False:
|
||||
if analytics.need_to_ask(args.analytics):
|
||||
io.tool_output(
|
||||
"Aider respects your privacy and never collects your code, chat messages, keys or"
|
||||
" personal info."
|
||||
@@ -529,9 +551,11 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
|
||||
if args.gui and not return_coder:
|
||||
if not check_streamlit_install(io):
|
||||
analytics.event("exit", reason="Streamlit not installed")
|
||||
return
|
||||
analytics.event("gui session")
|
||||
launch_gui(argv)
|
||||
analytics.event("exit", reason="GUI session ended")
|
||||
return
|
||||
|
||||
if args.verbose:
|
||||
@@ -540,7 +564,14 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
|
||||
all_files = args.files + (args.file or [])
|
||||
fnames = [str(Path(fn).resolve()) for fn in all_files]
|
||||
read_only_fnames = [str(Path(fn).resolve()) for fn in (args.read or [])]
|
||||
read_only_fnames = []
|
||||
for fn in args.read or []:
|
||||
path = Path(fn).resolve()
|
||||
if path.is_dir():
|
||||
read_only_fnames.extend(str(f) for f in path.rglob("*") if f.is_file())
|
||||
else:
|
||||
read_only_fnames.append(str(path))
|
||||
|
||||
if len(all_files) > 1:
|
||||
good = True
|
||||
for fname in all_files:
|
||||
@@ -551,6 +582,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
io.tool_output(
|
||||
"Provide either a single directory of a git repo, or a list of one or more files."
|
||||
)
|
||||
analytics.event("exit", reason="Invalid directory input")
|
||||
return 1
|
||||
|
||||
git_dname = None
|
||||
@@ -561,6 +593,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
fnames = []
|
||||
else:
|
||||
io.tool_error(f"{all_files[0]} is a directory, but --no-git selected.")
|
||||
analytics.event("exit", reason="Directory with --no-git")
|
||||
return 1
|
||||
|
||||
# We can't know the git repo for sure until after parsing the args.
|
||||
@@ -569,18 +602,22 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
if args.git and not force_git_root:
|
||||
right_repo_root = guessed_wrong_repo(io, git_root, fnames, git_dname)
|
||||
if right_repo_root:
|
||||
analytics.event("exit", reason="Recursing with correct repo")
|
||||
return main(argv, input, output, right_repo_root, return_coder=return_coder)
|
||||
|
||||
if args.just_check_update:
|
||||
update_available = check_version(io, just_check=True, verbose=args.verbose)
|
||||
analytics.event("exit", reason="Just checking update")
|
||||
return 0 if not update_available else 1
|
||||
|
||||
if args.install_main_branch:
|
||||
success = install_from_main_branch(io)
|
||||
analytics.event("exit", reason="Installed main branch")
|
||||
return 0 if success else 1
|
||||
|
||||
if args.upgrade:
|
||||
success = install_upgrade(io)
|
||||
analytics.event("exit", reason="Upgrade completed")
|
||||
return 0 if success else 1
|
||||
|
||||
if args.check_update:
|
||||
@@ -588,6 +625,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
|
||||
if args.list_models:
|
||||
models.print_matching_models(io, args.list_models)
|
||||
analytics.event("exit", reason="Listed models")
|
||||
return 0
|
||||
|
||||
if args.git:
|
||||
@@ -603,7 +641,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
cmd_line = scrub_sensitive_info(args, cmd_line)
|
||||
io.tool_output(cmd_line, log_only=True)
|
||||
|
||||
check_and_load_imports(io, verbose=args.verbose)
|
||||
is_first_run = is_first_run_of_new_version(io, verbose=args.verbose)
|
||||
check_and_load_imports(io, is_first_run, verbose=args.verbose)
|
||||
|
||||
if args.anthropic_api_key:
|
||||
os.environ["ANTHROPIC_API_KEY"] = args.anthropic_api_key
|
||||
@@ -622,6 +661,19 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
register_models(git_root, args.model_settings_file, io, verbose=args.verbose)
|
||||
register_litellm_models(git_root, args.model_metadata_file, io, verbose=args.verbose)
|
||||
|
||||
# Process any command line aliases
|
||||
if args.alias:
|
||||
for alias_def in args.alias:
|
||||
# Split on first colon only
|
||||
parts = alias_def.split(":", 1)
|
||||
if len(parts) != 2:
|
||||
io.tool_error(f"Invalid alias format: {alias_def}")
|
||||
io.tool_output("Format should be: alias:model-name")
|
||||
analytics.event("exit", reason="Invalid alias format error")
|
||||
return 1
|
||||
alias, model = parts
|
||||
models.MODEL_ALIASES[alias.strip()] = model.strip()
|
||||
|
||||
if not args.model:
|
||||
args.model = "gpt-4o-2024-08-06"
|
||||
if os.environ.get("ANTHROPIC_API_KEY"):
|
||||
@@ -635,11 +687,18 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
)
|
||||
|
||||
if args.verbose:
|
||||
io.tool_output("Model info:")
|
||||
io.tool_output("Model metadata:")
|
||||
io.tool_output(json.dumps(main_model.info, indent=4))
|
||||
|
||||
io.tool_output("Model settings:")
|
||||
for attr in sorted(fields(ModelSettings), key=lambda x: x.name):
|
||||
val = getattr(main_model, attr.name)
|
||||
val = json.dumps(val, indent=4)
|
||||
io.tool_output(f"{attr.name}: {val}")
|
||||
|
||||
lint_cmds = parse_lint_cmds(args.lint_cmd, io)
|
||||
if lint_cmds is None:
|
||||
analytics.event("exit", reason="Invalid lint command format")
|
||||
return 1
|
||||
|
||||
if args.show_model_warnings:
|
||||
@@ -652,6 +711,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
io.offer_url(urls.model_warnings, "Open documentation url for more info?")
|
||||
io.tool_output()
|
||||
except KeyboardInterrupt:
|
||||
analytics.event("exit", reason="Keyboard interrupt during model warnings")
|
||||
return 1
|
||||
|
||||
repo = None
|
||||
@@ -675,10 +735,22 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
|
||||
if not args.skip_sanity_check_repo:
|
||||
if not sanity_check_repo(repo, io):
|
||||
analytics.event("exit", reason="Repository sanity check failed")
|
||||
return 1
|
||||
|
||||
if repo:
|
||||
analytics.event("repo", num_files=len(repo.get_tracked_files()))
|
||||
else:
|
||||
analytics.event("no-repo")
|
||||
|
||||
commands = Commands(
|
||||
io, None, verify_ssl=args.verify_ssl, args=args, parser=parser, verbose=args.verbose
|
||||
io,
|
||||
None,
|
||||
verify_ssl=args.verify_ssl,
|
||||
args=args,
|
||||
parser=parser,
|
||||
verbose=args.verbose,
|
||||
editor=args.editor,
|
||||
)
|
||||
|
||||
summarizer = ChatSummary(
|
||||
@@ -726,12 +798,20 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
num_cache_warming_pings=args.cache_keepalive_pings,
|
||||
suggest_shell_commands=args.suggest_shell_commands,
|
||||
chat_language=args.chat_language,
|
||||
detect_urls=args.detect_urls,
|
||||
)
|
||||
except UnknownEditFormat as err:
|
||||
io.tool_error(str(err))
|
||||
io.offer_url(urls.edit_formats, "Open documentation about edit formats?")
|
||||
analytics.event("exit", reason="Unknown edit format")
|
||||
return 1
|
||||
except ValueError as err:
|
||||
io.tool_error(str(err))
|
||||
analytics.event("exit", reason="ValueError during coder creation")
|
||||
return 1
|
||||
|
||||
if return_coder:
|
||||
analytics.event("exit", reason="Returning coder object")
|
||||
return coder
|
||||
|
||||
coder.show_announcements()
|
||||
@@ -742,6 +822,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
]
|
||||
messages = coder.format_messages().all_messages()
|
||||
utils.show_messages(messages)
|
||||
analytics.event("exit", reason="Showed prompts")
|
||||
return
|
||||
|
||||
if args.lint:
|
||||
@@ -750,6 +831,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
if args.test:
|
||||
if not args.test_cmd:
|
||||
io.tool_error("No --test-cmd provided.")
|
||||
analytics.event("exit", reason="No test command provided")
|
||||
return 1
|
||||
test_errors = coder.commands.cmd_test(args.test_cmd)
|
||||
if test_errors:
|
||||
@@ -762,31 +844,41 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
coder.commands.cmd_commit()
|
||||
|
||||
if args.lint or args.test or args.commit:
|
||||
analytics.event("exit", reason="Completed lint/test/commit")
|
||||
return
|
||||
|
||||
if args.show_repo_map:
|
||||
repo_map = coder.get_repo_map()
|
||||
if repo_map:
|
||||
io.tool_output(repo_map)
|
||||
analytics.event("exit", reason="Showed repo map")
|
||||
return
|
||||
|
||||
if args.apply:
|
||||
content = io.read_text(args.apply)
|
||||
if content is None:
|
||||
analytics.event("exit", reason="Failed to read apply content")
|
||||
return
|
||||
coder.partial_response_content = content
|
||||
coder.apply_updates()
|
||||
analytics.event("exit", reason="Applied updates")
|
||||
return
|
||||
|
||||
if args.apply_clipboard_edits:
|
||||
args.edit_format = main_model.editor_edit_format
|
||||
args.message = "/paste"
|
||||
|
||||
if "VSCODE_GIT_IPC_HANDLE" in os.environ:
|
||||
args.pretty = False
|
||||
io.tool_output("VSCode terminal detected, pretty output has been disabled.")
|
||||
|
||||
io.tool_output('Use /help <question> for help, run "aider --help" to see cmd line args')
|
||||
if args.show_release_notes is True:
|
||||
io.tool_output(f"Opening release notes: {urls.release_notes}")
|
||||
io.tool_output()
|
||||
webbrowser.open(urls.release_notes)
|
||||
elif args.show_release_notes is None and is_first_run:
|
||||
io.tool_output()
|
||||
io.offer_url(
|
||||
urls.release_notes,
|
||||
"Would you like to see what's new in this version?",
|
||||
allow_never=False,
|
||||
)
|
||||
|
||||
if git_root and Path.cwd().resolve() != Path(git_root).resolve():
|
||||
io.tool_warning(
|
||||
@@ -807,6 +899,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
coder.run(with_message=args.message)
|
||||
except SwitchCoder:
|
||||
pass
|
||||
analytics.event("exit", reason="Completed --message")
|
||||
return
|
||||
|
||||
if args.message_file:
|
||||
@@ -816,13 +909,18 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
coder.run(with_message=message_from_file)
|
||||
except FileNotFoundError:
|
||||
io.tool_error(f"Message file not found: {args.message_file}")
|
||||
analytics.event("exit", reason="Message file not found")
|
||||
return 1
|
||||
except IOError as e:
|
||||
io.tool_error(f"Error reading message file: {e}")
|
||||
analytics.event("exit", reason="Message file IO error")
|
||||
return 1
|
||||
|
||||
analytics.event("exit", reason="Completed --message-file")
|
||||
return
|
||||
|
||||
if args.exit:
|
||||
analytics.event("exit", reason="Exit flag set")
|
||||
return
|
||||
|
||||
analytics.event("cli session", main_model=main_model, edit_format=main_model.edit_format)
|
||||
@@ -830,6 +928,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
while True:
|
||||
try:
|
||||
coder.run()
|
||||
analytics.event("exit", reason="Completed main CLI coder.run")
|
||||
return
|
||||
except SwitchCoder as switch:
|
||||
kwargs = dict(io=io, from_coder=coder)
|
||||
@@ -843,10 +942,15 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||
coder.show_announcements()
|
||||
|
||||
|
||||
def check_and_load_imports(io, verbose=False):
|
||||
def is_first_run_of_new_version(io, verbose=False):
|
||||
"""Check if this is the first run of a new version/executable combination"""
|
||||
installs_file = Path.home() / ".aider" / "installs.json"
|
||||
key = (__version__, sys.executable)
|
||||
|
||||
# Never show notes for .dev versions
|
||||
if ".dev" in __version__:
|
||||
return False
|
||||
|
||||
if verbose:
|
||||
io.tool_output(
|
||||
f"Checking imports for version {__version__} and executable {sys.executable}"
|
||||
@@ -864,7 +968,26 @@ def check_and_load_imports(io, verbose=False):
|
||||
if verbose:
|
||||
io.tool_output("Installs file does not exist, creating new dictionary")
|
||||
|
||||
if str(key) not in installs:
|
||||
is_first_run = str(key) not in installs
|
||||
|
||||
if is_first_run:
|
||||
installs[str(key)] = True
|
||||
installs_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(installs_file, "w") as f:
|
||||
json.dump(installs, f, indent=4)
|
||||
|
||||
return is_first_run
|
||||
|
||||
except Exception as e:
|
||||
io.tool_warning(f"Error checking version: {e}")
|
||||
if verbose:
|
||||
io.tool_output(f"Full exception details: {traceback.format_exc()}")
|
||||
return True # Safer to assume it's a first run if we hit an error
|
||||
|
||||
|
||||
def check_and_load_imports(io, is_first_run, verbose=False):
|
||||
try:
|
||||
if is_first_run:
|
||||
if verbose:
|
||||
io.tool_output(
|
||||
"First run for this version and executable, loading imports synchronously"
|
||||
@@ -875,13 +998,8 @@ def check_and_load_imports(io, verbose=False):
|
||||
io.tool_error(str(err))
|
||||
io.tool_output("Error loading required imports. Did you install aider properly?")
|
||||
io.offer_url(urls.install_properly, "Open documentation url for more info?")
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
installs[str(key)] = True
|
||||
installs_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(installs_file, "w") as f:
|
||||
json.dump(installs, f, indent=4)
|
||||
if verbose:
|
||||
io.tool_output("Imports loaded and installs file updated")
|
||||
else:
|
||||
@@ -890,8 +1008,9 @@ def check_and_load_imports(io, verbose=False):
|
||||
thread = threading.Thread(target=load_slow_imports)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
except Exception as e:
|
||||
io.tool_warning(f"Error in checking imports: {e}")
|
||||
io.tool_warning(f"Error in loading imports: {e}")
|
||||
if verbose:
|
||||
io.tool_output(f"Full exception details: {traceback.format_exc()}")
|
||||
|
||||
|
||||
114
aider/models.py
114
aider/models.py
@@ -17,7 +17,7 @@ from aider.dump import dump # noqa: F401
|
||||
from aider.llm import litellm
|
||||
|
||||
DEFAULT_MODEL_NAME = "gpt-4o"
|
||||
ANTHROPIC_BETA_HEADER = "prompt-caching-2024-07-31"
|
||||
ANTHROPIC_BETA_HEADER = "prompt-caching-2024-07-31,pdfs-2024-09-25"
|
||||
|
||||
OPENAI_MODELS = """
|
||||
gpt-4
|
||||
@@ -61,6 +61,23 @@ claude-3-5-sonnet-20241022
|
||||
|
||||
ANTHROPIC_MODELS = [ln.strip() for ln in ANTHROPIC_MODELS.splitlines() if ln.strip()]
|
||||
|
||||
# Mapping of model aliases to their canonical names
|
||||
MODEL_ALIASES = {
|
||||
# Claude models
|
||||
"sonnet": "claude-3-5-sonnet-20241022",
|
||||
"haiku": "claude-3-5-haiku-20241022",
|
||||
"opus": "claude-3-opus-20240229",
|
||||
# GPT models
|
||||
"4": "gpt-4-0613",
|
||||
"4o": "gpt-4o-2024-08-06",
|
||||
"4-turbo": "gpt-4-1106-preview",
|
||||
"35turbo": "gpt-3.5-turbo",
|
||||
"35-turbo": "gpt-3.5-turbo",
|
||||
"3": "gpt-3.5-turbo",
|
||||
# Other models
|
||||
"deepseek": "deepseek/deepseek-coder",
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModelSettings:
|
||||
@@ -161,6 +178,22 @@ MODEL_SETTINGS = [
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
),
|
||||
ModelSettings(
|
||||
"gpt-4o-2024-11-20",
|
||||
"diff",
|
||||
weak_model_name="gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
),
|
||||
ModelSettings(
|
||||
"openai/gpt-4o-2024-11-20",
|
||||
"diff",
|
||||
weak_model_name="gpt-4o-mini",
|
||||
use_repo_map=True,
|
||||
lazy=True,
|
||||
reminder="sys",
|
||||
),
|
||||
ModelSettings(
|
||||
"gpt-4o",
|
||||
"diff",
|
||||
@@ -629,7 +662,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"azure/o1-mini",
|
||||
@@ -641,7 +673,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"o1-mini",
|
||||
@@ -653,7 +684,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openai/o1-preview",
|
||||
@@ -665,7 +695,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"azure/o1-preview",
|
||||
@@ -677,7 +706,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"o1-preview",
|
||||
@@ -689,7 +717,6 @@ MODEL_SETTINGS = [
|
||||
reminder="user",
|
||||
use_system_prompt=False,
|
||||
use_temperature=False,
|
||||
streaming=False,
|
||||
),
|
||||
ModelSettings(
|
||||
"openrouter/openai/o1-mini",
|
||||
@@ -762,6 +789,11 @@ class ModelInfoManager:
|
||||
pass
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
try:
|
||||
# Save empty dict to cache file on failure
|
||||
self.cache_file.write_text("{}")
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def get_model_from_cached_json_db(self, model):
|
||||
if not self.content:
|
||||
@@ -804,11 +836,20 @@ model_info_manager = ModelInfoManager()
|
||||
|
||||
class Model(ModelSettings):
|
||||
def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None):
|
||||
# Map any alias to its canonical name
|
||||
model = MODEL_ALIASES.get(model, model)
|
||||
|
||||
self.name = model
|
||||
|
||||
self.max_chat_history_tokens = 1024
|
||||
self.weak_model = None
|
||||
self.editor_model = None
|
||||
|
||||
# Find the extra settings
|
||||
self.extra_model_settings = next(
|
||||
(ms for ms in MODEL_SETTINGS if ms.name == "aider/extra_params"), None
|
||||
)
|
||||
|
||||
self.info = self.get_model_info(model)
|
||||
|
||||
# Are all needed keys/params available?
|
||||
@@ -836,17 +877,44 @@ class Model(ModelSettings):
|
||||
def get_model_info(self, model):
|
||||
return model_info_manager.get_model_info(model)
|
||||
|
||||
def _copy_fields(self, source):
|
||||
"""Helper to copy fields from a ModelSettings instance to self"""
|
||||
for field in fields(ModelSettings):
|
||||
val = getattr(source, field.name)
|
||||
setattr(self, field.name, val)
|
||||
|
||||
def configure_model_settings(self, model):
|
||||
# Look for exact model match
|
||||
exact_match = False
|
||||
for ms in MODEL_SETTINGS:
|
||||
# direct match, or match "provider/<model>"
|
||||
if model == ms.name:
|
||||
for field in fields(ModelSettings):
|
||||
val = getattr(ms, field.name)
|
||||
setattr(self, field.name, val)
|
||||
return # <--
|
||||
self._copy_fields(ms)
|
||||
exact_match = True
|
||||
break # Continue to apply overrides
|
||||
|
||||
model = model.lower()
|
||||
|
||||
# If no exact match, try generic settings
|
||||
if not exact_match:
|
||||
self.apply_generic_model_settings(model)
|
||||
|
||||
# Apply override settings last if they exist
|
||||
if self.extra_model_settings and self.extra_model_settings.extra_params:
|
||||
# Initialize extra_params if it doesn't exist
|
||||
if not self.extra_params:
|
||||
self.extra_params = {}
|
||||
|
||||
# Deep merge the extra_params dicts
|
||||
for key, value in self.extra_model_settings.extra_params.items():
|
||||
if isinstance(value, dict) and isinstance(self.extra_params.get(key), dict):
|
||||
# For nested dicts, merge recursively
|
||||
self.extra_params[key] = {**self.extra_params[key], **value}
|
||||
else:
|
||||
# For non-dict values, simply update
|
||||
self.extra_params[key] = value
|
||||
|
||||
def apply_generic_model_settings(self, model):
|
||||
if ("llama3" in model or "llama-3" in model) and "70b" in model:
|
||||
self.edit_format = "diff"
|
||||
self.use_repo_map = True
|
||||
@@ -868,27 +936,37 @@ class Model(ModelSettings):
|
||||
|
||||
if "gpt-3.5" in model or "gpt-4" in model:
|
||||
self.reminder = "sys"
|
||||
return # <--
|
||||
|
||||
if "3.5-sonnet" in model or "3-5-sonnet" in model:
|
||||
self.edit_format = "diff"
|
||||
self.use_repo_map = True
|
||||
self.examples_as_sys_msg = True
|
||||
self.reminder = "user"
|
||||
return # <--
|
||||
|
||||
if model.startswith("o1-") or "/o1-" in model:
|
||||
self.use_system_prompt = False
|
||||
self.use_temperature = False
|
||||
self.streaming = False
|
||||
return # <--
|
||||
|
||||
if "qwen" in model and "coder" in model and ("2.5" in model or "2-5" in model):
|
||||
"openrouter/qwen/qwen-2.5-coder-32b-instruct",
|
||||
if (
|
||||
"qwen" in model
|
||||
and "coder" in model
|
||||
and ("2.5" in model or "2-5" in model)
|
||||
and "32b" in model
|
||||
):
|
||||
self.edit_format = "diff"
|
||||
self.editor_edit_format = "editor-diff"
|
||||
self.use_repo_map = True
|
||||
if model.startswith("ollama/") or model.startswith("ollama_chat/"):
|
||||
self.extra_params = dict(num_ctx=8 * 1024)
|
||||
return # <--
|
||||
|
||||
# use the defaults
|
||||
if self.edit_format == "diff":
|
||||
self.use_repo_map = True
|
||||
return # <--
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@@ -1045,6 +1123,9 @@ def register_models(model_settings_fnames):
|
||||
if not os.path.exists(model_settings_fname):
|
||||
continue
|
||||
|
||||
if not Path(model_settings_fname).read_text().strip():
|
||||
continue
|
||||
|
||||
try:
|
||||
with open(model_settings_fname, "r") as model_settings_file:
|
||||
model_settings_list = yaml.safe_load(model_settings_file)
|
||||
@@ -1162,7 +1243,10 @@ def fuzzy_match_models(name):
|
||||
model = model.lower()
|
||||
if attrs.get("mode") != "chat":
|
||||
continue
|
||||
provider = (attrs["litellm_provider"] + "/").lower()
|
||||
provider = attrs.get("litellm_provider", "").lower()
|
||||
if not provider:
|
||||
continue
|
||||
provider += "/"
|
||||
|
||||
if model.startswith(provider):
|
||||
fq_model = model
|
||||
|
||||
91
aider/queries/tree-sitter-dart-tags.scm
Normal file
91
aider/queries/tree-sitter-dart-tags.scm
Normal file
@@ -0,0 +1,91 @@
|
||||
(class_definition
|
||||
name: (identifier) @name.definition.class) @definition.class
|
||||
|
||||
(method_signature
|
||||
(function_signature)) @definition.method
|
||||
|
||||
(type_alias
|
||||
(type_identifier) @name.definition.type) @definition.type
|
||||
|
||||
(method_signature
|
||||
(getter_signature
|
||||
name: (identifier) @name.definition.method)) @definition.method
|
||||
|
||||
(method_signature
|
||||
(setter_signature
|
||||
name: (identifier) @name.definition.method)) @definition.method
|
||||
|
||||
(method_signature
|
||||
(function_signature
|
||||
name: (identifier) @name.definition.method)) @definition.method
|
||||
|
||||
(method_signature
|
||||
(factory_constructor_signature
|
||||
(identifier) @name.definition.method)) @definition.method
|
||||
|
||||
(method_signature
|
||||
(constructor_signature
|
||||
name: (identifier) @name.definition.method)) @definition.method
|
||||
|
||||
(method_signature
|
||||
(operator_signature)) @definition.method
|
||||
|
||||
(method_signature) @definition.method
|
||||
|
||||
(mixin_declaration
|
||||
(mixin)
|
||||
(identifier) @name.definition.mixin) @definition.mixin
|
||||
|
||||
(extension_declaration
|
||||
name: (identifier) @name.definition.extension) @definition.extension
|
||||
|
||||
(enum_declaration
|
||||
name: (identifier) @name.definition.enum) @definition.enum
|
||||
|
||||
(function_signature
|
||||
name: (identifier) @name.definition.function) @definition.function
|
||||
|
||||
(new_expression
|
||||
(type_identifier) @name.reference.class) @reference.class
|
||||
|
||||
(initialized_variable_definition
|
||||
name: (identifier)
|
||||
value: (identifier) @name.reference.class
|
||||
value: (selector
|
||||
"!"?
|
||||
(argument_part
|
||||
(arguments
|
||||
(argument)*))?)?) @reference.class
|
||||
|
||||
(assignment_expression
|
||||
left: (assignable_expression
|
||||
(identifier)
|
||||
(unconditional_assignable_selector
|
||||
"."
|
||||
(identifier) @name.reference.call))) @reference.call
|
||||
|
||||
(assignment_expression
|
||||
left: (assignable_expression
|
||||
(identifier)
|
||||
(conditional_assignable_selector
|
||||
"?."
|
||||
(identifier) @name.reference.call))) @reference.call
|
||||
|
||||
((identifier) @name
|
||||
(selector
|
||||
"!"?
|
||||
(conditional_assignable_selector
|
||||
"?." (identifier) @name.reference.call)?
|
||||
(unconditional_assignable_selector
|
||||
"."? (identifier) @name.reference.call)?
|
||||
(argument_part
|
||||
(arguments
|
||||
(argument)*))?)*
|
||||
(cascade_section
|
||||
(cascade_selector
|
||||
(identifier)) @name.reference.call
|
||||
(argument_part
|
||||
(arguments
|
||||
(argument)*))?)?) @reference.call
|
||||
|
||||
|
||||
@@ -334,8 +334,11 @@ class GitRepo:
|
||||
def git_ignored_file(self, path):
|
||||
if not self.repo:
|
||||
return
|
||||
if self.repo.ignored(path):
|
||||
return True
|
||||
try:
|
||||
if self.repo.ignored(path):
|
||||
return True
|
||||
except ANY_GIT_ERROR:
|
||||
return False
|
||||
|
||||
def ignored_file(self, fname):
|
||||
self.refresh_aider_ignore()
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"openrouter/qwen/qwen-2.5-coder-32b-instruct": {
|
||||
"max_tokens": 33792,
|
||||
"max_input_tokens": 33792,
|
||||
"max_output_tokens": 33792,
|
||||
"input_cost_per_token": 0.00000018,
|
||||
"output_cost_per_token": 0.00000018,
|
||||
"litellm_provider": "openrouter",
|
||||
"mode": "chat",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ import pexpect
|
||||
import psutil
|
||||
|
||||
|
||||
def run_cmd(command, verbose=False, error_print=None):
|
||||
def run_cmd(command, verbose=False, error_print=None, cwd=None):
|
||||
try:
|
||||
if sys.stdin.isatty() and hasattr(pexpect, "spawn") and platform.system() != "Windows":
|
||||
return run_cmd_pexpect(command, verbose)
|
||||
return run_cmd_pexpect(command, verbose, cwd)
|
||||
|
||||
return run_cmd_subprocess(command, verbose)
|
||||
return run_cmd_subprocess(command, verbose, cwd)
|
||||
except OSError as e:
|
||||
error_message = f"Error occurred while running command '{command}': {str(e)}"
|
||||
if error_print is None:
|
||||
@@ -39,7 +39,7 @@ def get_windows_parent_process_name():
|
||||
return None
|
||||
|
||||
|
||||
def run_cmd_subprocess(command, verbose=False):
|
||||
def run_cmd_subprocess(command, verbose=False, cwd=None):
|
||||
if verbose:
|
||||
print("Using run_cmd_subprocess:", command)
|
||||
|
||||
@@ -69,6 +69,7 @@ def run_cmd_subprocess(command, verbose=False):
|
||||
errors="replace",
|
||||
bufsize=0, # Set bufsize to 0 for unbuffered output
|
||||
universal_newlines=True,
|
||||
cwd=cwd,
|
||||
)
|
||||
|
||||
output = []
|
||||
@@ -85,7 +86,7 @@ def run_cmd_subprocess(command, verbose=False):
|
||||
return 1, str(e)
|
||||
|
||||
|
||||
def run_cmd_pexpect(command, verbose=False):
|
||||
def run_cmd_pexpect(command, verbose=False, cwd=None):
|
||||
"""
|
||||
Run a shell command interactively using pexpect, capturing all output.
|
||||
|
||||
@@ -112,12 +113,12 @@ def run_cmd_pexpect(command, verbose=False):
|
||||
# Use the shell from SHELL environment variable
|
||||
if verbose:
|
||||
print("Running pexpect.spawn with shell:", shell)
|
||||
child = pexpect.spawn(shell, args=["-c", command], encoding="utf-8")
|
||||
child = pexpect.spawn(shell, args=["-c", command], encoding="utf-8", cwd=cwd)
|
||||
else:
|
||||
# Fall back to spawning the command directly
|
||||
if verbose:
|
||||
print("Running pexpect.spawn without shell.")
|
||||
child = pexpect.spawn(command, encoding="utf-8")
|
||||
child = pexpect.spawn(command, encoding="utf-8", cwd=cwd)
|
||||
|
||||
# Transfer control to the user, capturing output
|
||||
child.interact(output_filter=output_callback)
|
||||
|
||||
@@ -12,3 +12,5 @@ github_issues = "https://github.com/Aider-AI/aider/issues/new"
|
||||
git_index_version = "https://github.com/Aider-AI/aider/issues/211"
|
||||
install_properly = "https://aider.chat/docs/troubleshooting/imports.html"
|
||||
analytics = "https://aider.chat/docs/more/analytics.html"
|
||||
release_notes = "https://aider.chat/HISTORY.html#release-notes"
|
||||
edit_formats = "https://aider.chat/docs/more/edit-formats.html"
|
||||
|
||||
@@ -13,7 +13,7 @@ import git
|
||||
|
||||
from aider.dump import dump # noqa: F401
|
||||
|
||||
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".webp"}
|
||||
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".webp", ".pdf"}
|
||||
|
||||
|
||||
class IgnorantTemporaryDirectory:
|
||||
|
||||
@@ -34,7 +34,7 @@ class Voice:
|
||||
|
||||
threshold = 0.15
|
||||
|
||||
def __init__(self, audio_format="wav"):
|
||||
def __init__(self, audio_format="wav", device_name=None):
|
||||
if sf is None:
|
||||
raise SoundDeviceError
|
||||
try:
|
||||
@@ -42,6 +42,27 @@ class Voice:
|
||||
import sounddevice as sd
|
||||
|
||||
self.sd = sd
|
||||
|
||||
|
||||
devices = sd.query_devices()
|
||||
|
||||
if device_name:
|
||||
# Find the device with matching name
|
||||
device_id = None
|
||||
for i, device in enumerate(devices):
|
||||
if device_name in device["name"]:
|
||||
device_id = i
|
||||
break
|
||||
if device_id is None:
|
||||
available_inputs = [d["name"] for d in devices if d["max_input_channels"] > 0]
|
||||
raise ValueError(f"Device '{device_name}' not found. Available input devices: {available_inputs}")
|
||||
|
||||
print(f"Using input device: {device_name} (ID: {device_id})")
|
||||
|
||||
self.device_id = device_id
|
||||
else:
|
||||
self.device_id = None
|
||||
|
||||
except (OSError, ModuleNotFoundError):
|
||||
raise SoundDeviceError
|
||||
if audio_format not in ["wav", "mp3", "webm"]:
|
||||
@@ -93,7 +114,7 @@ class Voice:
|
||||
temp_wav = tempfile.mktemp(suffix=".wav")
|
||||
|
||||
try:
|
||||
sample_rate = int(self.sd.query_devices(None, "input")["default_samplerate"])
|
||||
sample_rate = int(self.sd.query_devices(self.device_id, "input")["default_samplerate"])
|
||||
except (TypeError, ValueError):
|
||||
sample_rate = 16000 # fallback to 16kHz if unable to query device
|
||||
except self.sd.PortAudioError:
|
||||
@@ -104,7 +125,7 @@ class Voice:
|
||||
self.start_time = time.time()
|
||||
|
||||
try:
|
||||
with self.sd.InputStream(samplerate=sample_rate, channels=1, callback=self.callback):
|
||||
with self.sd.InputStream(samplerate=sample_rate, channels=1, callback=self.callback, device=self.device_id):
|
||||
prompt(self.get_prompt, refresh_interval=0.1)
|
||||
except self.sd.PortAudioError as err:
|
||||
raise SoundDeviceError(f"Error accessing audio input device: {err}")
|
||||
|
||||
@@ -10,6 +10,12 @@ description: Release notes and stats on aider writing its own code.
|
||||
|
||||
{% include blame.md %}
|
||||
|
||||
The above
|
||||
[stats are based on the git commit history](/docs/faq.html#how-are-the-aider-wrote-xx-of-code-stats-computed)
|
||||
of the aider repo.
|
||||
|
||||
## Release notes
|
||||
|
||||
<!--[[[cog
|
||||
# This page is a copy of HISTORY.md, adding the front matter above.
|
||||
text = open("HISTORY.md").read()
|
||||
@@ -18,6 +24,75 @@ cog.out(text)
|
||||
]]]-->
|
||||
|
||||
|
||||
### main branch
|
||||
|
||||
- PDF support for Sonnet and Gemini models.
|
||||
- Added `--voice-input-device` to select audio input device for voice recording, by @preynal.
|
||||
- Added `--timeout` option to configure API call timeouts.
|
||||
- Set cwd to repo root when running shell commands.
|
||||
- Added Ctrl-Up/Down keyboard shortcuts for per-message history navigation.
|
||||
- Improved error handling for failed .gitignore file operations.
|
||||
- Improved error handling for input history file permissions.
|
||||
- Improved error handling for analytics file access.
|
||||
- Removed spurious warning about disabling pretty in VSCode.
|
||||
- Removed broken support for Dart.
|
||||
- Bugfix when scraping URLs found in chat messages.
|
||||
- Better handling of __version__ import errors.
|
||||
- Improved `/drop` command to support substring matching for non-glob patterns.
|
||||
- Aider wrote 82% of the code in this release.
|
||||
|
||||
### Aider v0.65.1
|
||||
|
||||
- Bugfix to `--alias`.
|
||||
|
||||
### Aider v0.65.0
|
||||
|
||||
- Added `--alias` config to define [custom model aliases](https://aider.chat/docs/config/model-aliases.html).
|
||||
- Added `--[no-]detect-urls` flag to disable detecting and offering to scrape URLs found in the chat.
|
||||
- Ollama models now default to an 8k context window.
|
||||
- Added [RepoMap support for Dart language](https://aider.chat/docs/languages.html) by @malkoG.
|
||||
- Ask 2.5% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html).
|
||||
- Skip suggesting files that share names with files already in chat.
|
||||
- `/editor` returns and prefill the file content into the prompt, so you can use `/editor` to compose messages that start with `/commands`, etc.
|
||||
- Enhanced error handling for analytics.
|
||||
- Improved handling of UnknownEditFormat exceptions with helpful documentation links.
|
||||
- Bumped dependencies to pick up grep-ast 0.4.0 for Dart language support.
|
||||
- Aider wrote 81% of the code in this release.
|
||||
|
||||
### Aider v0.64.1
|
||||
|
||||
- Disable streaming for o1 on OpenRouter.
|
||||
|
||||
### Aider v0.64.0
|
||||
|
||||
- Added [`/editor` command](https://aider.chat/docs/usage/commands.html) to open system editor for writing prompts, by @thehunmonkgroup.
|
||||
- Full support for `gpt-4o-2024-11-20`.
|
||||
- Stream o1 models by default.
|
||||
- `/run` and suggested shell commands are less mysterious and now confirm that they "Added XX lines of output to the chat."
|
||||
- Ask 1% of users if they want to opt-in to [analytics](https://aider.chat/docs/more/analytics.html).
|
||||
- Added support for [optional multiline input tags](https://aider.chat/docs/usage/commands.html#entering-multi-line-chat-messages) with matching closing tags.
|
||||
- Improved [model settings configuration](https://aider.chat/docs/config/adv-model-settings.html#global-extra-params) with support for global `extra_params` for `litellm.completion()`.
|
||||
- Architect mode now asks to add files suggested by the LLM.
|
||||
- Fixed bug in fuzzy model name matching.
|
||||
- Added Timeout exception to handle API provider timeouts.
|
||||
- Added `--show-release-notes` to control release notes display on first run of new version.
|
||||
- Save empty dict to cache file on model metadata download failure, to delay retry.
|
||||
- Improved error handling and code formatting.
|
||||
- Aider wrote 74% of the code in this release.
|
||||
|
||||
### Aider v0.63.2
|
||||
|
||||
- Fixed bug in fuzzy model name matching when litellm provider info is missing.
|
||||
- Modified model metadata file loading to allow override of resource file.
|
||||
- Allow recursive loading of dirs using `--read`.
|
||||
- Updated dependency versions to pick up litellm fix for ollama models.
|
||||
- Added exponential backoff retry when writing files to handle editor file locks.
|
||||
- Updated Qwen 2.5 Coder 32B model configuration.
|
||||
|
||||
### Aider v0.63.1
|
||||
|
||||
- Fixed bug in git ignored file handling.
|
||||
- Improved error handling for git operations.
|
||||
|
||||
### Aider v0.63.0
|
||||
|
||||
|
||||
@@ -1801,8 +1801,8 @@
|
||||
Paul Gauthier (aider): 113
|
||||
start_tag: v0.44.0
|
||||
total_lines: 266
|
||||
- aider_percentage: 47.04
|
||||
aider_total: 254
|
||||
- aider_percentage: 53.3
|
||||
aider_total: 339
|
||||
end_date: '2024-07-29'
|
||||
end_tag: v0.46.0
|
||||
file_counts:
|
||||
@@ -1853,6 +1853,9 @@
|
||||
aider/scrape.py:
|
||||
Paul Gauthier: 3
|
||||
Paul Gauthier (aider): 32
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 11
|
||||
Paul Gauthier (aider): 85
|
||||
benchmark/Dockerfile:
|
||||
Your Name: 1
|
||||
tests/basic/test_coder.py:
|
||||
@@ -1868,13 +1871,13 @@
|
||||
Paul Gauthier (aider): 73
|
||||
grand_total:
|
||||
Charles Joachim: 4
|
||||
Paul Gauthier: 209
|
||||
Paul Gauthier (aider): 204
|
||||
Paul Gauthier: 220
|
||||
Paul Gauthier (aider): 289
|
||||
Your Name: 73
|
||||
Your Name (aider): 50
|
||||
start_tag: v0.45.0
|
||||
total_lines: 540
|
||||
- aider_percentage: 59.12
|
||||
total_lines: 636
|
||||
- aider_percentage: 57.16
|
||||
aider_total: 415
|
||||
end_date: '2024-07-31'
|
||||
end_tag: v0.47.0
|
||||
@@ -1920,6 +1923,8 @@
|
||||
Paul Gauthier (aider): 2
|
||||
aider/utils.py:
|
||||
Paul Gauthier: 7
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 24
|
||||
docker/Dockerfile:
|
||||
Paul Gauthier: 19
|
||||
Paul Gauthier (aider): 21
|
||||
@@ -1944,10 +1949,10 @@
|
||||
tests/basic/test_repomap.py:
|
||||
Paul Gauthier: 1
|
||||
grand_total:
|
||||
Paul Gauthier: 287
|
||||
Paul Gauthier: 311
|
||||
Paul Gauthier (aider): 415
|
||||
start_tag: v0.46.0
|
||||
total_lines: 702
|
||||
total_lines: 726
|
||||
- aider_percentage: 44.44
|
||||
aider_total: 276
|
||||
end_date: '2024-08-06'
|
||||
@@ -2011,8 +2016,8 @@
|
||||
paul-gauthier: 1
|
||||
start_tag: v0.47.0
|
||||
total_lines: 621
|
||||
- aider_percentage: 61.52
|
||||
aider_total: 478
|
||||
- aider_percentage: 61.2
|
||||
aider_total: 489
|
||||
end_date: '2024-08-10'
|
||||
end_tag: v0.49.0
|
||||
file_counts:
|
||||
@@ -2055,6 +2060,9 @@
|
||||
aider/versioncheck.py:
|
||||
Paul Gauthier: 3
|
||||
Paul Gauthier (aider): 11
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 11
|
||||
Paul Gauthier (aider): 11
|
||||
docker/Dockerfile:
|
||||
Paul Gauthier: 5
|
||||
Paul Gauthier (aider): 2
|
||||
@@ -2075,10 +2083,10 @@
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 49
|
||||
grand_total:
|
||||
Paul Gauthier: 299
|
||||
Paul Gauthier (aider): 478
|
||||
Paul Gauthier: 310
|
||||
Paul Gauthier (aider): 489
|
||||
start_tag: v0.48.0
|
||||
total_lines: 777
|
||||
total_lines: 799
|
||||
- aider_percentage: 66.05
|
||||
aider_total: 214
|
||||
end_date: '2024-08-13'
|
||||
@@ -2135,8 +2143,8 @@
|
||||
Paul Gauthier (aider): 201
|
||||
start_tag: v0.49.0
|
||||
total_lines: 324
|
||||
- aider_percentage: 56.25
|
||||
aider_total: 450
|
||||
- aider_percentage: 52.49
|
||||
aider_total: 580
|
||||
end_date: '2024-08-20'
|
||||
end_tag: v0.51.0
|
||||
file_counts:
|
||||
@@ -2170,6 +2178,14 @@
|
||||
Paul Gauthier: 3
|
||||
aider/utils.py:
|
||||
Paul Gauthier (aider): 6
|
||||
aider/website/_includes/code-in-json-benchmark.js:
|
||||
Paul Gauthier: 101
|
||||
Paul Gauthier (aider): 64
|
||||
aider/website/_includes/code-in-json-syntax.js:
|
||||
Paul Gauthier: 73
|
||||
Paul Gauthier (aider): 66
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 7
|
||||
benchmark/over_time.py:
|
||||
@@ -2188,11 +2204,11 @@
|
||||
Paul Gauthier: 15
|
||||
Paul Gauthier (aider): 104
|
||||
grand_total:
|
||||
Paul Gauthier: 350
|
||||
Paul Gauthier (aider): 450
|
||||
Paul Gauthier: 525
|
||||
Paul Gauthier (aider): 580
|
||||
start_tag: v0.50.0
|
||||
total_lines: 800
|
||||
- aider_percentage: 68.19
|
||||
total_lines: 1105
|
||||
- aider_percentage: 68.1
|
||||
aider_total: 521
|
||||
end_date: '2024-08-23'
|
||||
end_tag: v0.52.0
|
||||
@@ -2231,6 +2247,8 @@
|
||||
Paul Gauthier (aider): 9
|
||||
aider/versioncheck.py:
|
||||
Paul Gauthier: 2
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 1
|
||||
scripts/blame.py:
|
||||
@@ -2250,13 +2268,13 @@
|
||||
tests/basic/test_wholefile.py:
|
||||
Paul Gauthier: 8
|
||||
grand_total:
|
||||
Paul Gauthier: 242
|
||||
Paul Gauthier: 243
|
||||
Paul Gauthier (aider): 521
|
||||
pcamp: 1
|
||||
start_tag: v0.51.0
|
||||
total_lines: 764
|
||||
- aider_percentage: 58.61
|
||||
aider_total: 405
|
||||
total_lines: 765
|
||||
- aider_percentage: 61.4
|
||||
aider_total: 455
|
||||
end_date: '2024-08-27'
|
||||
end_tag: v0.53.0
|
||||
file_counts:
|
||||
@@ -2321,14 +2339,16 @@
|
||||
tests/basic/test_repomap.py:
|
||||
Paul Gauthier: 4
|
||||
Paul Gauthier (aider): 63
|
||||
tests/fixtures/sample-code-base/sample.js:
|
||||
Paul Gauthier (aider): 50
|
||||
tests/fixtures/sample-code-base/sample.py:
|
||||
Paul Gauthier (aider): 68
|
||||
grand_total:
|
||||
Paul Gauthier: 286
|
||||
Paul Gauthier (aider): 405
|
||||
Paul Gauthier (aider): 455
|
||||
start_tag: v0.52.0
|
||||
total_lines: 691
|
||||
- aider_percentage: 63.95
|
||||
total_lines: 741
|
||||
- aider_percentage: 63.75
|
||||
aider_total: 204
|
||||
end_date: '2024-08-28'
|
||||
end_tag: v0.54.0
|
||||
@@ -2364,6 +2384,8 @@
|
||||
aider/versioncheck.py:
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 13
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
tests/basic/test_coder.py:
|
||||
Paul Gauthier: 36
|
||||
Paul Gauthier (aider): 27
|
||||
@@ -2376,11 +2398,11 @@
|
||||
Paul Gauthier: 1
|
||||
grand_total:
|
||||
Antti Kaihola: 4
|
||||
Paul Gauthier: 111
|
||||
Paul Gauthier: 112
|
||||
Paul Gauthier (aider): 204
|
||||
start_tag: v0.53.0
|
||||
total_lines: 319
|
||||
- aider_percentage: 52.9
|
||||
total_lines: 320
|
||||
- aider_percentage: 52.87
|
||||
aider_total: 811
|
||||
end_date: '2024-09-04'
|
||||
end_tag: v0.55.0
|
||||
@@ -2450,6 +2472,8 @@
|
||||
aider/voice.py:
|
||||
Paul Gauthier: 7
|
||||
Paul Gauthier (aider): 9
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
scripts/versionbump.py:
|
||||
Paul Gauthier: 9
|
||||
tests/basic/test_coder.py:
|
||||
@@ -2478,11 +2502,11 @@
|
||||
grand_total:
|
||||
Antti Kaihola: 12
|
||||
Nikolay Sedelnikov: 45
|
||||
Paul Gauthier: 665
|
||||
Paul Gauthier: 666
|
||||
Paul Gauthier (aider): 811
|
||||
start_tag: v0.54.0
|
||||
total_lines: 1533
|
||||
- aider_percentage: 55.6
|
||||
total_lines: 1534
|
||||
- aider_percentage: 55.4
|
||||
aider_total: 154
|
||||
end_date: '2024-09-09'
|
||||
end_tag: v0.56.0
|
||||
@@ -2517,6 +2541,8 @@
|
||||
aider/report.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 20
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 1
|
||||
tests/basic/test_linter.py:
|
||||
@@ -2526,13 +2552,13 @@
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 9
|
||||
grand_total:
|
||||
Paul Gauthier: 108
|
||||
Paul Gauthier: 109
|
||||
Paul Gauthier (aider): 154
|
||||
fry69: 15
|
||||
start_tag: v0.55.0
|
||||
total_lines: 277
|
||||
- aider_percentage: 69.98
|
||||
aider_total: 394
|
||||
total_lines: 278
|
||||
- aider_percentage: 70.36
|
||||
aider_total: 406
|
||||
end_date: '2024-09-21'
|
||||
end_tag: v0.57.0
|
||||
file_counts:
|
||||
@@ -2575,6 +2601,10 @@
|
||||
Paul Gauthier: 3
|
||||
aider/utils.py:
|
||||
Paul Gauthier: 2
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Anjor Kanekar: 1
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 12
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 4
|
||||
scripts/issues.py:
|
||||
@@ -2592,15 +2622,16 @@
|
||||
Paul Gauthier: 18
|
||||
Paul Gauthier (aider): 20
|
||||
grand_total:
|
||||
Anjor Kanekar: 1
|
||||
Christian Clauss: 2
|
||||
Jay Alammar: 1
|
||||
Jay Alammar (aider): 13
|
||||
Krazer: 33
|
||||
Paul Gauthier: 133
|
||||
Paul Gauthier (aider): 381
|
||||
Paul Gauthier: 134
|
||||
Paul Gauthier (aider): 393
|
||||
start_tag: v0.56.0
|
||||
total_lines: 563
|
||||
- aider_percentage: 53.45
|
||||
total_lines: 577
|
||||
- aider_percentage: 47.95
|
||||
aider_total: 712
|
||||
end_date: '2024-09-29'
|
||||
end_tag: v0.58.0
|
||||
@@ -2677,6 +2708,8 @@
|
||||
Mike Bailey: 17
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 10
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 153
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier: 25
|
||||
Paul Gauthier (aider): 29
|
||||
@@ -2705,14 +2738,14 @@
|
||||
grand_total:
|
||||
Jonathan Ellis: 2
|
||||
Mike Bailey: 18
|
||||
Paul Gauthier: 376
|
||||
Paul Gauthier: 529
|
||||
Paul Gauthier (aider): 712
|
||||
Stein Martin Hustad: 26
|
||||
fry69: 197
|
||||
rti: 1
|
||||
start_tag: v0.57.0
|
||||
total_lines: 1332
|
||||
- aider_percentage: 76.79
|
||||
total_lines: 1485
|
||||
- aider_percentage: 75.44
|
||||
aider_total: 172
|
||||
end_date: '2024-10-04'
|
||||
end_tag: v0.59.0
|
||||
@@ -2747,6 +2780,8 @@
|
||||
Paul Gauthier: 2
|
||||
aider/versioncheck.py:
|
||||
Paul Gauthier: 1
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 4
|
||||
scripts/issues.py:
|
||||
Paul Gauthier: 1
|
||||
scripts/update-docs.sh:
|
||||
@@ -2762,11 +2797,11 @@
|
||||
tests/help/test_help.py:
|
||||
Paul Gauthier: 1
|
||||
grand_total:
|
||||
Paul Gauthier: 52
|
||||
Paul Gauthier: 56
|
||||
Paul Gauthier (aider): 172
|
||||
start_tag: v0.58.0
|
||||
total_lines: 224
|
||||
- aider_percentage: 49.12
|
||||
total_lines: 228
|
||||
- aider_percentage: 48.95
|
||||
aider_total: 140
|
||||
end_date: '2024-10-22'
|
||||
end_tag: v0.60.0
|
||||
@@ -2804,6 +2839,8 @@
|
||||
Paul Gauthier: 3
|
||||
aider/sendchat.py:
|
||||
Paul Gauthier: 3
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
tests/basic/test_editblock.py:
|
||||
Paul Gauthier: 23
|
||||
tests/basic/test_main.py:
|
||||
@@ -2813,12 +2850,12 @@
|
||||
Paul Gauthier (aider): 46
|
||||
grand_total:
|
||||
Jonathan Ellis: 10
|
||||
Paul Gauthier: 93
|
||||
Paul Gauthier: 94
|
||||
Paul Gauthier (aider): 140
|
||||
Sven Grunewaldt: 24
|
||||
fry69: 18
|
||||
start_tag: v0.59.0
|
||||
total_lines: 285
|
||||
total_lines: 286
|
||||
- aider_percentage: 67.61
|
||||
aider_total: 860
|
||||
end_date: '2024-11-01'
|
||||
@@ -2895,8 +2932,8 @@
|
||||
kAIto47802: 4
|
||||
start_tag: v0.60.0
|
||||
total_lines: 1272
|
||||
- aider_percentage: 84.0
|
||||
aider_total: 63
|
||||
- aider_percentage: 82.42
|
||||
aider_total: 75
|
||||
end_date: '2024-11-04'
|
||||
end_tag: v0.62.0
|
||||
file_counts:
|
||||
@@ -2911,8 +2948,224 @@
|
||||
aider/models.py:
|
||||
Paul Gauthier: 5
|
||||
Paul Gauthier (aider): 45
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 4
|
||||
Paul Gauthier (aider): 12
|
||||
grand_total:
|
||||
Paul Gauthier: 12
|
||||
Paul Gauthier (aider): 63
|
||||
Paul Gauthier: 16
|
||||
Paul Gauthier (aider): 75
|
||||
start_tag: v0.61.0
|
||||
total_lines: 75
|
||||
total_lines: 91
|
||||
- aider_percentage: 55.08
|
||||
aider_total: 385
|
||||
end_date: '2024-11-13'
|
||||
end_tag: v0.63.0
|
||||
file_counts:
|
||||
aider/__init__.py:
|
||||
Paul Gauthier: 1
|
||||
aider/coders/architect_coder.py:
|
||||
Paul Gauthier: 3
|
||||
aider/coders/base_coder.py:
|
||||
Paul Gauthier: 42
|
||||
Paul Gauthier (aider): 1
|
||||
aider/coders/editblock_coder.py:
|
||||
Paul Gauthier: 4
|
||||
aider/commands.py:
|
||||
Paul Gauthier: 13
|
||||
aider/exceptions.py:
|
||||
Paul Gauthier: 72
|
||||
Paul Gauthier (aider): 4
|
||||
aider/io.py:
|
||||
Paul Gauthier: 3
|
||||
Paul Gauthier (aider): 23
|
||||
aider/main.py:
|
||||
Paul Gauthier: 9
|
||||
Paul Gauthier (aider): 9
|
||||
aider/models.py:
|
||||
Logan Attwood: 29
|
||||
Paul Gauthier: 50
|
||||
Paul Gauthier (aider): 7
|
||||
aider/repo.py:
|
||||
Paul Gauthier: 7
|
||||
aider/repomap.py:
|
||||
Paul Gauthier: 4
|
||||
aider/sendchat.py:
|
||||
Paul Gauthier: 17
|
||||
Paul Gauthier (aider): 4
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
scripts/issues.py:
|
||||
Paul Gauthier: 4
|
||||
Paul Gauthier (aider): 195
|
||||
tests/basic/test_coder.py:
|
||||
Paul Gauthier: 2
|
||||
tests/basic/test_commands.py:
|
||||
Paul Gauthier (aider): 20
|
||||
tests/basic/test_editblock.py:
|
||||
Paul Gauthier: 41
|
||||
tests/basic/test_exceptions.py:
|
||||
Paul Gauthier (aider): 65
|
||||
tests/basic/test_main.py:
|
||||
Paul Gauthier: 1
|
||||
tests/basic/test_sanity_check_repo.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 2
|
||||
tests/basic/test_sendchat.py:
|
||||
Paul Gauthier: 8
|
||||
Paul Gauthier (aider): 55
|
||||
tests/scrape/test_scrape.py:
|
||||
Paul Gauthier: 1
|
||||
grand_total:
|
||||
Logan Attwood: 29
|
||||
Paul Gauthier: 285
|
||||
Paul Gauthier (aider): 385
|
||||
start_tag: v0.62.0
|
||||
total_lines: 699
|
||||
- aider_percentage: 73.15
|
||||
aider_total: 880
|
||||
end_date: '2024-11-21'
|
||||
end_tag: v0.64.0
|
||||
file_counts:
|
||||
aider/__init__.py:
|
||||
Paul Gauthier: 1
|
||||
aider/analytics.py:
|
||||
Paul Gauthier: 20
|
||||
Paul Gauthier (aider): 21
|
||||
aider/args.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 10
|
||||
aider/coders/base_coder.py:
|
||||
Paul Gauthier: 15
|
||||
Paul Gauthier (aider): 3
|
||||
caetanominuzzo: 1
|
||||
aider/commands.py:
|
||||
Chad Phillips: 4
|
||||
Paul Gauthier: 5
|
||||
Paul Gauthier (aider): 19
|
||||
aider/editor.py:
|
||||
Chad Phillips: 133
|
||||
Paul Gauthier (aider): 13
|
||||
aider/exceptions.py:
|
||||
Paul Gauthier: 5
|
||||
aider/help_pats.py:
|
||||
Paul Gauthier: 1
|
||||
aider/io.py:
|
||||
Chad Phillips: 9
|
||||
Paul Gauthier (aider): 41
|
||||
mw: 21
|
||||
aider/main.py:
|
||||
Paul Gauthier: 21
|
||||
Paul Gauthier (aider): 41
|
||||
aider/models.py:
|
||||
Paul Gauthier: 41
|
||||
Paul Gauthier (aider): 33
|
||||
aider/repo.py:
|
||||
Paul Gauthier (aider): 5
|
||||
aider/urls.py:
|
||||
Paul Gauthier: 1
|
||||
aider/website/_includes/edit-leaderboard.js:
|
||||
Paul Gauthier (aider): 97
|
||||
aider/website/_includes/quant-chart.js:
|
||||
Paul Gauthier: 3
|
||||
Paul Gauthier (aider): 66
|
||||
aider/website/_includes/refactor-leaderboard.js:
|
||||
Paul Gauthier (aider): 90
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 10
|
||||
aider/website/share/index.md:
|
||||
Paul Gauthier (aider): 29
|
||||
benchmark/over_time.py:
|
||||
Paul Gauthier: 11
|
||||
Paul Gauthier (aider): 162
|
||||
scripts/blame.py:
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 2
|
||||
scripts/issues.py:
|
||||
Paul Gauthier: 5
|
||||
Paul Gauthier (aider): 12
|
||||
scripts/versionbump.py:
|
||||
Paul Gauthier: 7
|
||||
tests/basic/test_analytics.py:
|
||||
Paul Gauthier: 12
|
||||
Paul Gauthier (aider): 30
|
||||
tests/basic/test_commands.py:
|
||||
Paul Gauthier (aider): 4
|
||||
tests/basic/test_editor.py:
|
||||
Paul Gauthier (aider): 129
|
||||
tests/basic/test_main.py:
|
||||
Paul Gauthier (aider): 8
|
||||
tests/basic/test_models.py:
|
||||
Paul Gauthier: 3
|
||||
Paul Gauthier (aider): 55
|
||||
grand_total:
|
||||
Chad Phillips: 146
|
||||
Paul Gauthier: 155
|
||||
Paul Gauthier (aider): 880
|
||||
caetanominuzzo: 1
|
||||
mw: 21
|
||||
start_tag: v0.63.0
|
||||
total_lines: 1203
|
||||
- aider_percentage: 81.11
|
||||
aider_total: 584
|
||||
end_date: '2024-11-26'
|
||||
end_tag: v0.65.0
|
||||
file_counts:
|
||||
aider/__init__.py:
|
||||
Paul Gauthier: 1
|
||||
aider/analytics.py:
|
||||
Paul Gauthier: 2
|
||||
Paul Gauthier (aider): 5
|
||||
aider/args.py:
|
||||
Paul Gauthier (aider): 12
|
||||
aider/coders/base_coder.py:
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 31
|
||||
aider/commands.py:
|
||||
Paul Gauthier: 2
|
||||
aider/io.py:
|
||||
Paul Gauthier: 3
|
||||
Paul Gauthier (aider): 9
|
||||
aider/main.py:
|
||||
Paul Gauthier: 15
|
||||
Paul Gauthier (aider): 19
|
||||
aider/models.py:
|
||||
Paul Gauthier: 9
|
||||
Paul Gauthier (aider): 17
|
||||
aider/queries/tree-sitter-dart-tags.scm:
|
||||
malkoG: 91
|
||||
aider/urls.py:
|
||||
Paul Gauthier (aider): 1
|
||||
aider/website/_includes/quant-chart.js:
|
||||
Paul Gauthier (aider): 76
|
||||
aider/website/docs/leaderboards/index.md:
|
||||
Paul Gauthier: 1
|
||||
benchmark/benchmark.py:
|
||||
Paul Gauthier (aider): 10
|
||||
benchmark/docker.sh:
|
||||
Paul Gauthier (aider): 1
|
||||
benchmark/over_time.py:
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 157
|
||||
scripts/update-docs.sh:
|
||||
Paul Gauthier: 1
|
||||
scripts/update-history.py:
|
||||
Paul Gauthier: 8
|
||||
Paul Gauthier (aider): 64
|
||||
tests/basic/test_coder.py:
|
||||
Paul Gauthier (aider): 81
|
||||
tests/basic/test_editor.py:
|
||||
Paul Gauthier (aider): 16
|
||||
tests/basic/test_main.py:
|
||||
Paul Gauthier: 1
|
||||
Paul Gauthier (aider): 42
|
||||
tests/basic/test_models.py:
|
||||
Paul Gauthier (aider): 30
|
||||
tests/basic/test_repomap.py:
|
||||
Paul Gauthier (aider): 13
|
||||
grand_total:
|
||||
Paul Gauthier: 45
|
||||
Paul Gauthier (aider): 584
|
||||
malkoG: 91
|
||||
start_tag: v0.64.0
|
||||
total_lines: 720
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
- dirname: 2024-05-01-20-05-59--direct-opus-filenames-outside-fence
|
||||
test_cases: 133
|
||||
model: claude-3-opus-20240229
|
||||
released: 2024-02-29
|
||||
_released: 2024-02-29
|
||||
edit_format: diff
|
||||
commit_hash: f4b1797-dirty, f4b1797
|
||||
pass_rate_1: 53.4
|
||||
@@ -46,7 +46,8 @@
|
||||
|
||||
- dirname: 2024-05-03-20-47-24--gemini-1.5-pro-diff-fenced
|
||||
test_cases: 133
|
||||
model: gemini-1.5-pro-latest
|
||||
released: 2024-05-03
|
||||
model: gemini-1.5-pro-001
|
||||
edit_format: diff-fenced
|
||||
commit_hash: 3a48dfb, 5d32dd7
|
||||
pass_rate_1: 45.9
|
||||
@@ -274,7 +275,7 @@
|
||||
- dirname: 2024-05-03-22-24-48--openrouter--llama3-diff-examples-sys-msg
|
||||
test_cases: 132
|
||||
model: llama3-70b-8192
|
||||
released: 2024-04-18
|
||||
_released: 2024-04-18
|
||||
edit_format: diff
|
||||
commit_hash: b5bb453
|
||||
pass_rate_1: 38.6
|
||||
@@ -297,7 +298,7 @@
|
||||
- dirname: 2024-05-06-18-31-08--command-r-plus-whole-final
|
||||
test_cases: 133
|
||||
model: command-r-plus
|
||||
released: 2024-04-04
|
||||
_released: 2024-04-04
|
||||
edit_format: whole
|
||||
commit_hash: fc3a43e-dirty
|
||||
pass_rate_1: 21.8
|
||||
@@ -410,6 +411,7 @@
|
||||
- dirname: 2024-06-08-22-37-55--qwen2-72b-instruct-whole
|
||||
test_cases: 133
|
||||
model: Qwen2 72B Instruct
|
||||
released: 2024-06-08
|
||||
edit_format: whole
|
||||
commit_hash: 02c7335-dirty, 1a97498-dirty
|
||||
pass_rate_1: 44.4
|
||||
@@ -623,7 +625,7 @@
|
||||
commit_hash: d31eef3-dirty
|
||||
pass_rate_1: 40.6
|
||||
pass_rate_2: 55.6
|
||||
released: 2024-07-18
|
||||
_released: 2024-07-18
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 1
|
||||
num_malformed_responses: 0
|
||||
@@ -671,7 +673,7 @@
|
||||
commit_hash: f7ce78b-dirty
|
||||
pass_rate_1: 46.6
|
||||
pass_rate_2: 63.9
|
||||
released: 2024-07-23
|
||||
_released: 2024-07-23
|
||||
percent_cases_well_formed: 92.5
|
||||
error_outputs: 84
|
||||
num_malformed_responses: 19
|
||||
@@ -691,6 +693,7 @@
|
||||
- dirname: 2024-07-24-06-30-29--llama-405b-whole
|
||||
test_cases: 133
|
||||
model: llama-3.1-405b-instruct (whole)
|
||||
_released: 2024-07-23
|
||||
edit_format: whole
|
||||
commit_hash: a362dea-dirty
|
||||
pass_rate_1: 48.9
|
||||
@@ -698,7 +701,6 @@
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
released: 2024-07-23
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 0
|
||||
lazy_comments: 0
|
||||
@@ -770,7 +772,7 @@
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 27
|
||||
num_malformed_responses: 0
|
||||
released: 2024-07-23
|
||||
_released: 2024-07-23
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 23
|
||||
lazy_comments: 8
|
||||
@@ -796,7 +798,7 @@
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 0
|
||||
released: 2024-07-23
|
||||
_released: 2024-07-23
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
@@ -835,6 +837,7 @@
|
||||
- dirname: 2024-08-28-07-10-50--gemini-1.5-pro-exp-0827-diff-fenced
|
||||
test_cases: 133
|
||||
model: gemini-1.5-pro-exp-0827
|
||||
released: 2024-08-27
|
||||
edit_format: diff-fenced
|
||||
commit_hash: d8adc75
|
||||
pass_rate_1: 54.9
|
||||
@@ -946,7 +949,7 @@
|
||||
versions: 0.54.13.dev
|
||||
seconds_per_case: 8.3
|
||||
total_cost: 0.0000
|
||||
released: 2024-09-04
|
||||
_released: 2024-09-04
|
||||
|
||||
- dirname: 2024-09-04-16-17-33--yi-coder-9b-chat-q4_0-whole
|
||||
test_cases: 133
|
||||
@@ -973,6 +976,7 @@
|
||||
|
||||
- dirname: 2024-09-05-14-50-11--deepseek-sep5-no-shell
|
||||
test_cases: 133
|
||||
released: 2024-09-05
|
||||
model: DeepSeek V2.5
|
||||
edit_format: diff
|
||||
commit_hash: 1279c86
|
||||
@@ -1112,6 +1116,7 @@
|
||||
- dirname: 2024-09-21-16-45-11--o1-preview-flex-sr-markers
|
||||
test_cases: 133
|
||||
model: o1-preview
|
||||
_released: 2024-09-12
|
||||
edit_format: diff
|
||||
commit_hash: 5493654-dirty
|
||||
pass_rate_1: 57.9
|
||||
@@ -1204,6 +1209,7 @@
|
||||
- dirname: 2024-09-24-16-26-45--gemini-1.5-pro-002-diff-fenced
|
||||
test_cases: 133
|
||||
model: gemini-1.5-pro-002
|
||||
released: 2024-09-24
|
||||
edit_format: diff-fenced
|
||||
commit_hash: 6b5fe9b, 3edcd71
|
||||
pass_rate_1: 49.6
|
||||
@@ -1477,6 +1483,7 @@
|
||||
- dirname: 2024-10-04-16-30-08--chatgpt-4o-latest-diff-oct4
|
||||
test_cases: 133
|
||||
model: openai/chatgpt-4o-latest
|
||||
released: 2024-10-04
|
||||
edit_format: diff
|
||||
commit_hash: af10953
|
||||
pass_rate_1: 56.4
|
||||
@@ -1592,6 +1599,7 @@
|
||||
- dirname: 2024-10-22-17-45-28--sonnet-1022-diff-fixed-model-settings
|
||||
test_cases: 133
|
||||
model: claude-3-5-sonnet-20241022
|
||||
released: 2024-10-22
|
||||
edit_format: diff
|
||||
commit_hash: 3b14eb9
|
||||
pass_rate_1: 69.2
|
||||
@@ -1615,6 +1623,7 @@
|
||||
- dirname: 2024-11-04-19-19-32--haiku35-diff-ex-as-sys-false
|
||||
test_cases: 133
|
||||
model: claude-3-5-haiku-20241022
|
||||
released: 2024-10-22
|
||||
edit_format: diff
|
||||
commit_hash: 03bbdb0-dirty
|
||||
pass_rate_1: 61.7
|
||||
@@ -1773,32 +1782,10 @@
|
||||
seconds_per_case: 18.3
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-09-10-57-11--Qwen2.5-Coder-32B-Instruct
|
||||
test_cases: 133
|
||||
model: Qwen2.5-Coder-32B-Instruct (whole)
|
||||
edit_format: whole
|
||||
commit_hash: ec9982a
|
||||
pass_rate_1: 60.9
|
||||
pass_rate_2: 73.7
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 1
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 1
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 1
|
||||
test_timeouts: 1
|
||||
command: aider --model openai/Qwen2.5-Coder-32B-Instruct
|
||||
date: 2024-11-09
|
||||
versions: 0.59.2.dev
|
||||
seconds_per_case: 26.6
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-09-11-09-15--Qwen2.5-Coder-32B-Instruct
|
||||
test_cases: 133
|
||||
model: Qwen2.5-Coder-32B-Instruct (diff)
|
||||
model: Qwen2.5-Coder-32B-Instruct
|
||||
released: 2024-11-12
|
||||
edit_format: diff
|
||||
commit_hash: ec9982a
|
||||
pass_rate_1: 59.4
|
||||
@@ -1813,8 +1800,223 @@
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: aider --model openai/Qwen2.5-Coder-32B-Instruct
|
||||
command: aider --model openai/hf:Qwen/Qwen2.5-Coder-32B-Instruct --openai-api-base https://glhf.chat/api/openai/v1
|
||||
date: 2024-11-09
|
||||
versions: 0.59.2.dev
|
||||
seconds_per_case: 22.5
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-20-14-57-11--mistral-2411-direct-diff
|
||||
test_cases: 133
|
||||
model: Mistral Large (2411)
|
||||
released: 2024-11-18
|
||||
edit_format: diff
|
||||
commit_hash: dba844c
|
||||
pass_rate_1: 46.6
|
||||
pass_rate_2: 65.4
|
||||
percent_cases_well_formed: 96.2
|
||||
error_outputs: 8
|
||||
num_malformed_responses: 8
|
||||
num_with_malformed_responses: 5
|
||||
user_asks: 5
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 1
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 1
|
||||
command: aider --model mistral/mistral-large-latest
|
||||
date: 2024-11-20
|
||||
versions: 0.63.3.dev
|
||||
seconds_per_case: 24.9
|
||||
total_cost: 3.2334
|
||||
|
||||
- dirname: 2024-11-20-19-28-30--gpt-4o-2024-11-20
|
||||
test_cases: 133
|
||||
model: gpt-4o-2024-11-20
|
||||
released: 2024-11-20
|
||||
edit_format: diff
|
||||
commit_hash: 2ac0776-dirty
|
||||
pass_rate_1: 58.6
|
||||
pass_rate_2: 71.4
|
||||
percent_cases_well_formed: 99.2
|
||||
error_outputs: 1
|
||||
num_malformed_responses: 1
|
||||
num_with_malformed_responses: 1
|
||||
user_asks: 4
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 5
|
||||
command: aider --model openai/gpt-4o-2024-11-20
|
||||
date: 2024-11-20
|
||||
versions: 0.63.3.dev
|
||||
seconds_per_case: 6.0
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-09-20-21-47-17--qwen2.5-32b-instruct-q8_0-whole
|
||||
test_cases: 133
|
||||
model: ollama/qwen2.5:32b-instruct-q8_0
|
||||
edit_format: whole
|
||||
commit_hash: 2753ac6
|
||||
pass_rate_1: 46.6
|
||||
pass_rate_2: 58.6
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
user_asks: 1
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --model ollama/qwen2.5:32b-instruct-q8_0
|
||||
date: 2024-09-20
|
||||
versions: 0.56.1.dev
|
||||
seconds_per_case: 1763.7
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-20-15-17-37--qwen25-32b-or-diff
|
||||
test_cases: 133
|
||||
model: openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
edit_format: diff
|
||||
commit_hash: e917424
|
||||
pass_rate_1: 49.6
|
||||
pass_rate_2: 65.4
|
||||
percent_cases_well_formed: 84.2
|
||||
error_outputs: 43
|
||||
num_malformed_responses: 31
|
||||
num_with_malformed_responses: 21
|
||||
user_asks: 43
|
||||
lazy_comments: 0
|
||||
syntax_errors: 2
|
||||
indentation_errors: 2
|
||||
exhausted_context_windows: 12
|
||||
test_timeouts: 2
|
||||
command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
date: 2024-11-20
|
||||
versions: 0.63.3.dev
|
||||
seconds_per_case: 40.7
|
||||
total_cost: 0.1497
|
||||
|
||||
- dirname: 2024-11-21-17-46-36--gemini-exp-1121-diff
|
||||
test_cases: 133
|
||||
model: gemini-exp-1121
|
||||
released: 2024-11-21
|
||||
edit_format: diff
|
||||
commit_hash: e94961a
|
||||
pass_rate_1: 46.6
|
||||
pass_rate_2: 57.9
|
||||
percent_cases_well_formed: 83.5
|
||||
error_outputs: 101
|
||||
num_malformed_responses: 101
|
||||
num_with_malformed_responses: 22
|
||||
user_asks: 5
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 2
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: aider --model gemini/gemini-exp-1121
|
||||
date: 2024-11-21
|
||||
versions: 0.63.3.dev
|
||||
seconds_per_case: 60.3
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-15-20-33-31--gemini-exp-1114-diff
|
||||
test_cases: 133
|
||||
model: gemini-exp-1114
|
||||
released: 2024-11-14
|
||||
edit_format: diff
|
||||
commit_hash: 0bf17a4
|
||||
pass_rate_1: 50.4
|
||||
pass_rate_2: 60.9
|
||||
percent_cases_well_formed: 85.7
|
||||
error_outputs: 70
|
||||
num_malformed_responses: 70
|
||||
num_with_malformed_responses: 19
|
||||
user_asks: 2
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 4
|
||||
command: aider --model gemini/gemini-exp-1114
|
||||
date: 2024-11-15
|
||||
versions: 0.63.2.dev
|
||||
seconds_per_case: 38.6
|
||||
- dirname: 2024-11-27-07-41-51--qwen2.5-coder-14b-whole-1
|
||||
test_cases: 133
|
||||
model: ollama/qwen2.5-coder:14b
|
||||
edit_format: whole
|
||||
commit_hash: 200295e
|
||||
pass_rate_1: 53.4
|
||||
pass_rate_2: 61.7
|
||||
percent_cases_well_formed: 98.5
|
||||
error_outputs: 4
|
||||
num_malformed_responses: 4
|
||||
num_with_malformed_responses: 2
|
||||
user_asks: 48
|
||||
lazy_comments: 0
|
||||
syntax_errors: 2
|
||||
indentation_errors: 2
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --model ollama/qwen2.5-coder:14b
|
||||
date: 2024-11-27
|
||||
versions: 0.65.2.dev
|
||||
seconds_per_case: 58.0
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-28-07-42-56--qwen2.5-coder-32b-whole-4
|
||||
test_cases: 133
|
||||
model: ollama/qwen2.5-coder:32b
|
||||
edit_format: whole
|
||||
commit_hash: 200295e
|
||||
pass_rate_1: 58.6
|
||||
pass_rate_2: 72.9
|
||||
percent_cases_well_formed: 100.0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
command: aider --model ollama/qwen2.5-coder:32b
|
||||
date: 2024-11-28
|
||||
versions: 0.65.2.dev
|
||||
seconds_per_case: 147.5
|
||||
total_cost: 0.0000
|
||||
- dirname: 2024-11-28-13-14-00--tulu3-whole-2
|
||||
test_cases: 133
|
||||
model: ollama/tulu3
|
||||
edit_format: whole
|
||||
commit_hash: 200295e
|
||||
pass_rate_1: 21.8
|
||||
pass_rate_2: 26.3
|
||||
percent_cases_well_formed: 100.0
|
||||
error_outputs: 0
|
||||
num_malformed_responses: 0
|
||||
num_with_malformed_responses: 0
|
||||
exhausted_context_windows: 0
|
||||
command: aider --model ollama/tulu3
|
||||
date: 2024-11-28
|
||||
versions: 0.65.2.dev
|
||||
seconds_per_case: 35.8
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-28-14-41-46--granite3-dense-8b-whole-1
|
||||
test_cases: 133
|
||||
model: ollama/granite3-dense:8b
|
||||
edit_format: whole
|
||||
commit_hash: 200295e
|
||||
pass_rate_1: 17.3
|
||||
pass_rate_2: 20.3
|
||||
percent_cases_well_formed: 78.9
|
||||
exhausted_context_windows: 0
|
||||
command: aider --model ollama/granite3-dense:8b
|
||||
date: 2024-11-28
|
||||
versions: 0.65.2.dev
|
||||
seconds_per_case: 38.1
|
||||
total_cost: 0.0000
|
||||
|
||||
322
aider/website/_data/quant.yml
Normal file
322
aider/website/_data/quant.yml
Normal file
@@ -0,0 +1,322 @@
|
||||
- dirname: 2024-11-09-11-09-15--Qwen2.5-Coder-32B-Instruct
|
||||
test_cases: 133
|
||||
model: "HuggingFace via GLHF: BF16"
|
||||
released: 2024-11-12
|
||||
edit_format: diff
|
||||
commit_hash: ec9982a
|
||||
pass_rate_1: 59.4
|
||||
pass_rate_2: 71.4
|
||||
percent_cases_well_formed: 94.7
|
||||
error_outputs: 17
|
||||
num_malformed_responses: 17
|
||||
num_with_malformed_responses: 7
|
||||
user_asks: 1
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: aider --model openai/hf:Qwen/Qwen2.5-Coder-32B-Instruct --openai-api-base https://glhf.chat/api/openai/v1
|
||||
date: 2024-11-09
|
||||
versions: 0.59.2.dev
|
||||
seconds_per_case: 22.5
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-22-18-56-13--ollama-qwen2.5-coder:32b-instruct-fp16
|
||||
test_cases: 132
|
||||
model: "Ollama: fp16"
|
||||
edit_format: diff
|
||||
commit_hash: f06452c-dirty, 6a0a97c-dirty, 4e9ae16-dirty, 5506d0f-dirty
|
||||
pass_rate_1: 58.3
|
||||
pass_rate_2: 71.4
|
||||
percent_cases_well_formed: 90.2
|
||||
error_outputs: 27
|
||||
num_malformed_responses: 26
|
||||
num_with_malformed_responses: 13
|
||||
user_asks: 2
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 0
|
||||
command: aider --model ollama/qwen2.5-coder:32b-instruct-fp16
|
||||
date: 2024-11-22
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 119.6
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-22-14-53-26--hyperbolic-qwen25coder32binstruct
|
||||
test_cases: 133
|
||||
model: "Hyperbolic: BF16"
|
||||
edit_format: diff
|
||||
commit_hash: f9ef161, 17aef7b-dirty
|
||||
pass_rate_1: 57.9
|
||||
pass_rate_2: 69.2
|
||||
percent_cases_well_formed: 91.7
|
||||
error_outputs: 30
|
||||
num_malformed_responses: 29
|
||||
num_with_malformed_responses: 11
|
||||
user_asks: 9
|
||||
lazy_comments: 0
|
||||
syntax_errors: 4
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 2
|
||||
command: aider --model openai/Qwen/Qwen2.5-Coder-32B-Instruct --openai-api-base https://api.hyperbolic.xyz/v1/
|
||||
date: 2024-11-22
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 33.2
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-22-17-53-35--qwen25-coder-32b-Instruct-4bit
|
||||
test_cases: 133
|
||||
model: "mlx-community: 4bit"
|
||||
edit_format: diff
|
||||
commit_hash: a16dcab-dirty
|
||||
pass_rate_1: 60.2
|
||||
pass_rate_2: 72.2
|
||||
percent_cases_well_formed: 88.7
|
||||
error_outputs: 31
|
||||
num_malformed_responses: 30
|
||||
num_with_malformed_responses: 15
|
||||
user_asks: 6
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 1
|
||||
test_timeouts: 0
|
||||
command: aider --model openai/mlx-community/Qwen2.5-Coder-32B-Instruct-4bit
|
||||
date: 2024-11-23
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 53.4
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-23-15-07-20--qwen25-coder-32b-Instruct-8bit
|
||||
test_cases: 133
|
||||
model: "mlx-community: 8bit"
|
||||
edit_format: diff
|
||||
commit_hash: a16dcab-dirty
|
||||
pass_rate_1: 59.4
|
||||
pass_rate_2: 72.2
|
||||
percent_cases_well_formed: 92.5
|
||||
error_outputs: 20
|
||||
num_malformed_responses: 15
|
||||
num_with_malformed_responses: 10
|
||||
user_asks: 7
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 5
|
||||
test_timeouts: 2
|
||||
command: aider --model openai/mlx-community/Qwen2.5-Coder-32B-Instruct-8bit
|
||||
date: 2024-11-23
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 98.4
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-24-22-18-18--or-all-or-fixed-blank-messages2
|
||||
test_cases: 133
|
||||
model: "OpenRouter: multiple"
|
||||
edit_format: diff
|
||||
commit_hash: 0c59d32
|
||||
pass_rate_1: 57.1
|
||||
pass_rate_2: 67.7
|
||||
percent_cases_well_formed: 95.5
|
||||
error_outputs: 56
|
||||
num_malformed_responses: 10
|
||||
num_with_malformed_responses: 6
|
||||
user_asks: 14
|
||||
lazy_comments: 0
|
||||
syntax_errors: 6
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 3
|
||||
test_timeouts: 1
|
||||
command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
date: 2024-11-24
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 21.2
|
||||
total_cost: 0.1420
|
||||
|
||||
- dirname: 2024-11-23-21-08-53--ollama-qwen2.5-coder:32b-instruct-q4_K_M-8kctx
|
||||
test_cases: 133
|
||||
model: "Ollama: q4_K_M"
|
||||
edit_format: diff
|
||||
commit_hash: baa1335-dirty, e63df83-dirty, ff8c1aa-dirty
|
||||
pass_rate_1: 54.9
|
||||
pass_rate_2: 66.9
|
||||
percent_cases_well_formed: 94.0
|
||||
error_outputs: 21
|
||||
num_malformed_responses: 21
|
||||
num_with_malformed_responses: 8
|
||||
user_asks: 5
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 3
|
||||
command: aider --model ollama/qwen2.5-coder:32b-instruct-q4_K_M
|
||||
date: 2024-11-23
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 35.7
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-24-02-23-32--deepinfra-qwen-diff
|
||||
test_cases: 133
|
||||
model: "Deepinfra: BF16"
|
||||
edit_format: diff
|
||||
commit_hash: bb78e2f
|
||||
pass_rate_1: 58.6
|
||||
pass_rate_2: 72.2
|
||||
percent_cases_well_formed: 94.7
|
||||
error_outputs: 15
|
||||
num_malformed_responses: 13
|
||||
num_with_malformed_responses: 7
|
||||
user_asks: 3
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 2
|
||||
test_timeouts: 3
|
||||
command: aider --model deepinfra/Qwen/Qwen2.5-Coder-32B-Instruct
|
||||
date: 2024-11-24
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 17.5
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-24-04-12-58--fireworks-qwen-diff
|
||||
test_cases: 133
|
||||
model: "Fireworks: unknown"
|
||||
edit_format: diff
|
||||
commit_hash: 757eac0
|
||||
pass_rate_1: 57.9
|
||||
pass_rate_2: 72.2
|
||||
percent_cases_well_formed: 94.0
|
||||
error_outputs: 23
|
||||
num_malformed_responses: 19
|
||||
num_with_malformed_responses: 8
|
||||
user_asks: 8
|
||||
lazy_comments: 0
|
||||
syntax_errors: 6
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 4
|
||||
test_timeouts: 1
|
||||
command: aider --model fireworks_ai/accounts/fireworks/models/qwen2p5-coder-32b-instruct
|
||||
date: 2024-11-24
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 10.4
|
||||
total_cost: 0.5759
|
||||
|
||||
- dirname: 2024-11-24-02-04-59--ollama-qwen2.5-coder:32b-instruct-q2_K-8kctx
|
||||
test_cases: 133
|
||||
model: "Ollama: q2_K"
|
||||
edit_format: diff
|
||||
commit_hash: 757eac0, bb78e2f, 8d0ba40-dirty, 1d09e96
|
||||
pass_rate_1: 48.9
|
||||
pass_rate_2: 61.7
|
||||
percent_cases_well_formed: 91.7
|
||||
error_outputs: 32
|
||||
num_malformed_responses: 32
|
||||
num_with_malformed_responses: 11
|
||||
user_asks: 8
|
||||
lazy_comments: 0
|
||||
syntax_errors: 0
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 1
|
||||
command: aider --model ollama/qwen2.5-coder:32b-instruct-q2_K
|
||||
date: 2024-11-24
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 97.8
|
||||
total_cost: 0.0000
|
||||
|
||||
- dirname: 2024-11-24-14-56-49--qwen25-32b-or-fireworks
|
||||
test_cases: 133
|
||||
model: "Fireworks via OpenRouter: unknown"
|
||||
edit_format: diff
|
||||
commit_hash: c2f184f
|
||||
pass_rate_1: 55.6
|
||||
pass_rate_2: 67.7
|
||||
percent_cases_well_formed: 94.0
|
||||
error_outputs: 39
|
||||
num_malformed_responses: 24
|
||||
num_with_malformed_responses: 8
|
||||
user_asks: 13
|
||||
lazy_comments: 0
|
||||
syntax_errors: 1
|
||||
indentation_errors: 1
|
||||
exhausted_context_windows: 7
|
||||
test_timeouts: 4
|
||||
command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
date: 2024-11-24
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 16.1
|
||||
total_cost: 0.1391
|
||||
|
||||
- dirname: 2024-11-24-22-03-19--or-hyperbolic-or-fixed-blank-messages2
|
||||
test_cases: 133
|
||||
model: "Hyperbolic via OpenRouter: BF16"
|
||||
edit_format: diff
|
||||
commit_hash: 0c59d32
|
||||
pass_rate_1: 55.6
|
||||
pass_rate_2: 68.4
|
||||
percent_cases_well_formed: 89.5
|
||||
error_outputs: 28
|
||||
num_malformed_responses: 24
|
||||
num_with_malformed_responses: 14
|
||||
user_asks: 29
|
||||
lazy_comments: 0
|
||||
syntax_errors: 1
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 4
|
||||
test_timeouts: 1
|
||||
command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
date: 2024-11-24
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 41.5
|
||||
total_cost: 0.1402
|
||||
|
||||
- dirname: 2024-11-24-15-00-50--qwen25-32b-or-deepinfra
|
||||
test_cases: 133
|
||||
model: "Deepinfra via OpenRouter: BF16"
|
||||
edit_format: diff
|
||||
commit_hash: c2f184f
|
||||
pass_rate_1: 57.1
|
||||
pass_rate_2: 69.9
|
||||
percent_cases_well_formed: 89.5
|
||||
error_outputs: 35
|
||||
num_malformed_responses: 31
|
||||
num_with_malformed_responses: 14
|
||||
user_asks: 11
|
||||
lazy_comments: 0
|
||||
syntax_errors: 1
|
||||
indentation_errors: 1
|
||||
exhausted_context_windows: 4
|
||||
test_timeouts: 1
|
||||
command: aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct
|
||||
date: 2024-11-24
|
||||
versions: 0.64.2.dev
|
||||
seconds_per_case: 28.5
|
||||
total_cost: 0.1390
|
||||
|
||||
- dirname: 2024-11-26-03-15-06--ollama-qwen2.5-coder:32b-instruct-fp16-2kctx
|
||||
test_cases: 132
|
||||
model: "Ollama: fp16, 2k ctx"
|
||||
edit_format: diff
|
||||
commit_hash: 68be6c5-dirty, 554d274, 2ff3a23, 2ff3a23-dirty, 61759f9, dd48b74, 3ebd47d-dirty
|
||||
pass_rate_1: 43.2
|
||||
pass_rate_2: 51.9
|
||||
percent_cases_well_formed: 46.2
|
||||
error_outputs: 171
|
||||
num_malformed_responses: 165
|
||||
num_with_malformed_responses: 71
|
||||
user_asks: 97
|
||||
lazy_comments: 2
|
||||
syntax_errors: 4
|
||||
indentation_errors: 0
|
||||
exhausted_context_windows: 0
|
||||
test_timeouts: 0
|
||||
command: "aider --model ollama/qwen2.5-coder:32b-instruct-fp16 # num_ctx: 2048"
|
||||
date: 2024-11-26
|
||||
versions: 0.64.2.dev,0.65.1.dev
|
||||
seconds_per_case: 188.6
|
||||
total_cost: 0.0000
|
||||
97
aider/website/_includes/edit-leaderboard.js
Normal file
97
aider/website/_includes/edit-leaderboard.js
Normal file
@@ -0,0 +1,97 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('editChart').getContext('2d');
|
||||
const HIGHTLIGHT_MODEL = 'no no no no';
|
||||
var leaderboardData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: [],
|
||||
backgroundColor: function(context) {
|
||||
const label = context.chart.data.labels[context.dataIndex] || '';
|
||||
return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 0.2)' : 'rgba(54, 162, 235, 0.2)';
|
||||
},
|
||||
borderColor: function(context) {
|
||||
const label = context.chart.data.labels[context.dataIndex] || '';
|
||||
return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 1)' : 'rgba(54, 162, 235, 1)';
|
||||
},
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
|
||||
var allData = [];
|
||||
{% for row in edit_sorted %}
|
||||
allData.push({
|
||||
model: '{{ row.model }}',
|
||||
pass_rate_2: {{ row.pass_rate_2 }},
|
||||
percent_cases_well_formed: {{ row.percent_cases_well_formed }}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
function updateChart() {
|
||||
var selectedRows = document.querySelectorAll('tr.selected');
|
||||
var showAll = selectedRows.length === 0;
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
allData.forEach(function(row, index) {
|
||||
var rowElement = document.getElementById('edit-row-' + index);
|
||||
if (showAll) {
|
||||
rowElement.classList.remove('selected');
|
||||
}
|
||||
if (showAll || rowElement.classList.contains('selected')) {
|
||||
leaderboardData.labels.push(row.model);
|
||||
leaderboardData.datasets[0].data.push(row.pass_rate_2);
|
||||
}
|
||||
});
|
||||
|
||||
leaderboardChart.update();
|
||||
}
|
||||
|
||||
var tableBody = document.querySelector('table tbody');
|
||||
allData.forEach(function(row, index) {
|
||||
var tr = tableBody.children[index];
|
||||
tr.id = 'edit-row-' + index;
|
||||
tr.style.cursor = 'pointer';
|
||||
tr.onclick = function() {
|
||||
this.classList.toggle('selected');
|
||||
updateChart();
|
||||
};
|
||||
});
|
||||
|
||||
var leaderboardChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: leaderboardData,
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
|
||||
// Add search functionality for edit table
|
||||
document.getElementById('editSearchInput').addEventListener('keyup', function() {
|
||||
var searchWords = this.value.toLowerCase().split(' ').filter(word => word.length > 0);
|
||||
var tableBody = document.querySelector('table:first-of-type tbody');
|
||||
var rows = tableBody.getElementsByTagName('tr');
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var rowText = rows[i].textContent;
|
||||
if (searchWords.every(word => rowText.toLowerCase().includes(word))) {
|
||||
rows[i].style.display = '';
|
||||
leaderboardData.labels.push(allData[i].model);
|
||||
leaderboardData.datasets[0].data.push(allData[i].pass_rate_2);
|
||||
} else {
|
||||
rows[i].style.display = 'none';
|
||||
}
|
||||
}
|
||||
leaderboardChart.update();
|
||||
});
|
||||
});
|
||||
0
aider/website/_includes/leaderboard.js
Normal file
0
aider/website/_includes/leaderboard.js
Normal file
@@ -1,5 +1,19 @@
|
||||
You can send long, multi-line messages in the chat in a few ways:
|
||||
- Paste a multi-line message directly into the chat.
|
||||
- Enter `{` alone on the first line to start a multiline message and `}` alone on the last line to end it.
|
||||
- Or, start with `{tag` (where "tag" is any sequence of letters/numbers) and end with `tag}`. This is useful when you need to include closing braces `}` in your message.
|
||||
- Use Meta-ENTER to start a new line without sending the message (Esc+ENTER in some environments).
|
||||
- Use `/paste` to paste text from the clipboard into the chat.
|
||||
- Use the `/editor` command to open your editor to create the next chat message. See [editor configuration docs](/docs/config/editor.html) for more info.
|
||||
|
||||
Example with a tag:
|
||||
```
|
||||
{python
|
||||
def hello():
|
||||
print("Hello}") # Note: contains a brace
|
||||
python}
|
||||
```
|
||||
|
||||
{: .note }
|
||||
People often ask for SHIFT-ENTER to be a soft-newline.
|
||||
Unfortunately there is no portable way to detect that keystroke in terminals.
|
||||
|
||||
95
aider/website/_includes/quant-chart.js
Normal file
95
aider/website/_includes/quant-chart.js
Normal file
@@ -0,0 +1,95 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('quantChart').getContext('2d');
|
||||
var allData = [];
|
||||
{% for row in site.data.quant %}
|
||||
allData.push({
|
||||
model: '{{ row.model }}',
|
||||
pass_rate_2: {{ row.pass_rate_2 }}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
// Sort data by pass_rate_2 in descending order
|
||||
allData.sort((a, b) => b.pass_rate_2 - a.pass_rate_2);
|
||||
|
||||
var chart;
|
||||
|
||||
function updateChart(filterText) {
|
||||
var filteredData = allData.filter(row =>
|
||||
row.model.toLowerCase().includes(filterText.toLowerCase())
|
||||
);
|
||||
|
||||
var chartData = {
|
||||
labels: filteredData.map(row => row.model),
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: filteredData.map(row => row.pass_rate_2),
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
|
||||
if (chart) {
|
||||
chart.data = chartData;
|
||||
chart.update();
|
||||
} else {
|
||||
chart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: chartData,
|
||||
options: {
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Aider code editing benchmark',
|
||||
font: {
|
||||
size: 16
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Percent completed correctly',
|
||||
font: {
|
||||
size: 14
|
||||
}
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 16
|
||||
}
|
||||
}
|
||||
},
|
||||
x: {
|
||||
ticks: {
|
||||
font: {
|
||||
size: 16
|
||||
}
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Provider: quantization',
|
||||
font: {
|
||||
size: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Initial chart render
|
||||
updateChart('');
|
||||
|
||||
// Connect search input to chart filtering
|
||||
document.getElementById('quantSearchInput').addEventListener('keyup', function() {
|
||||
updateChart(this.value);
|
||||
});
|
||||
});
|
||||
90
aider/website/_includes/refactor-leaderboard.js
Normal file
90
aider/website/_includes/refactor-leaderboard.js
Normal file
@@ -0,0 +1,90 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('refacChart').getContext('2d');
|
||||
var leaderboardData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: [],
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
|
||||
var allData = [];
|
||||
{% for row in refac_sorted %}
|
||||
allData.push({
|
||||
model: '{{ row.model }}',
|
||||
pass_rate_1: {{ row.pass_rate_1 }},
|
||||
percent_cases_well_formed: {{ row.percent_cases_well_formed }}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
function updateChart() {
|
||||
var selectedRows = document.querySelectorAll('tr.selected');
|
||||
var showAll = selectedRows.length === 0;
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
allData.forEach(function(row, index) {
|
||||
var rowElement = document.getElementById('refac-row-' + index);
|
||||
if (showAll) {
|
||||
rowElement.classList.remove('selected');
|
||||
}
|
||||
if (showAll || rowElement.classList.contains('selected')) {
|
||||
leaderboardData.labels.push(row.model);
|
||||
leaderboardData.datasets[0].data.push(row.pass_rate_1);
|
||||
}
|
||||
});
|
||||
|
||||
leaderboardChart.update();
|
||||
}
|
||||
|
||||
var tableBody = document.querySelectorAll('table tbody')[1];
|
||||
allData.forEach(function(row, index) {
|
||||
var tr = tableBody.children[index];
|
||||
tr.id = 'refac-row-' + index;
|
||||
tr.style.cursor = 'pointer';
|
||||
tr.onclick = function() {
|
||||
this.classList.toggle('selected');
|
||||
updateChart();
|
||||
};
|
||||
});
|
||||
|
||||
var leaderboardChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: leaderboardData,
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
|
||||
// Add search functionality for refactoring table
|
||||
document.getElementById('refacSearchInput').addEventListener('keyup', function() {
|
||||
var searchWords = this.value.toLowerCase().split(' ').filter(word => word.length > 0);
|
||||
var tableBody = document.querySelectorAll('table tbody')[1];
|
||||
var rows = tableBody.getElementsByTagName('tr');
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var rowText = rows[i].textContent;
|
||||
if (searchWords.every(word => rowText.toLowerCase().includes(word))) {
|
||||
rows[i].style.display = '';
|
||||
leaderboardData.labels.push(allData[i].model);
|
||||
leaderboardData.datasets[0].data.push(allData[i].pass_rate_1);
|
||||
} else {
|
||||
rows[i].style.display = 'none';
|
||||
}
|
||||
}
|
||||
leaderboardChart.update();
|
||||
});
|
||||
});
|
||||
194
aider/website/_posts/2024-11-21-quantization.md
Normal file
194
aider/website/_posts/2024-11-21-quantization.md
Normal file
@@ -0,0 +1,194 @@
|
||||
---
|
||||
title: Details matter with open source models
|
||||
excerpt: Open source LLMs are becoming very powerful, but pay attention to how you (or your provider) are serving the model. It can affect code editing skill.
|
||||
highlight_image: /assets/quantization.jpg
|
||||
draft: false
|
||||
nav_exclude: true
|
||||
---
|
||||
{% if page.date %}
|
||||
<p class="post-date">{{ page.date | date: "%B %d, %Y" }}</p>
|
||||
{% endif %}
|
||||
|
||||
# Details matter with open source models
|
||||
{: .no_toc }
|
||||
|
||||
<canvas id="quantChart" width="800" height="600" style="margin: 20px 0"></canvas>
|
||||
|
||||
Open source models like Qwen 2.5 32B Instruct are performing very well on
|
||||
aider's code editing benchmark, rivaling closed source frontier models.
|
||||
|
||||
But pay attention to how your model is being served and quantized,
|
||||
as it can impact code editing skill.
|
||||
Open source models are often available at a variety of quantizations,
|
||||
and can be served with different token limits.
|
||||
These details matter when working with code.
|
||||
|
||||
The graph above and table below compares different versions of the Qwen 2.5 Coder 32B Instruct model,
|
||||
served both locally and from a variety of cloud providers.
|
||||
|
||||
- The [HuggingFace BF16 weights](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct) served via [glhf.chat](https://glhf.chat).
|
||||
- [4bit and 8bit quants for mlx](https://t.co/cwX3DYX35D).
|
||||
- The results from [OpenRouter's mix of providers](https://openrouter.ai/qwen/qwen-2.5-coder-32b-instruct/providers) which serve the model with different levels of quantization.
|
||||
- Results from OpenRouter's providers, both served via OpenRouter and directly to their own APIs.
|
||||
- Ollama locally serving different quantizations from the [Ollama model library](https://ollama.com/library/qwen2.5-coder:32b-instruct-q4_K_M) with 8k+
|
||||
context windows.
|
||||
- An Ollama fp16 quantization served with Ollama's default 2k context window.
|
||||
|
||||
### Pitfalls and details
|
||||
|
||||
This benchmarking effort highlighted a number of pitfalls and details specific to open source
|
||||
models which
|
||||
can have a significant impact on their ability to correctly edit code:
|
||||
|
||||
- **Quantization** -- Open source models are often available at dozens of different quantizations.
|
||||
Most seem to only modestly decrease code editing skill, but stronger quantizations
|
||||
do have a real impact.
|
||||
- **Context window** -- Cloud providers can decide how large a context window to accept,
|
||||
and they often choose differently. Ollama's local API server
|
||||
defaults to a tiny 2k context window,
|
||||
and silently discards data that exceeds it. Such a small window has
|
||||
catastrophic effects on performance, without throwing obvious hard errors.
|
||||
- **Output token limits** -- Open source models are often served with wildly
|
||||
differing output token limits. This has a direct impact on how much code the
|
||||
model can write or edit in a response.
|
||||
- **Buggy cloud providers** -- While benchmarking Qwen 2.5 Coder 32B Instruct
|
||||
and DeepSeek V2.5, I discovered
|
||||
multiple cloud providers with broken or buggy API endpoints.
|
||||
They seemed
|
||||
to be returning results different from expected based on the advertised
|
||||
quantization and context sizes.
|
||||
The harm caused to the code editing benchmark varied from serious
|
||||
to catastrophic.
|
||||
One provider scored 0.5% on the benchmark with DeepSeek V2.5, a highly capable model.
|
||||
|
||||
Closed source, proprietary models don't typically have these issues.
|
||||
They are owned and operated by the organization that created them,
|
||||
and typically served with specific, predictable context window and output token limits.
|
||||
Their quantization level is usually unknown, but fixed and unchanging for all users.
|
||||
|
||||
### Conclusions
|
||||
|
||||
The best versions of the Qwen model rival GPT-4o, while the worst performing
|
||||
quantization is more like the older GPT-4 Turbo when served competently.
|
||||
Even an otherwise excellent fp16 quantization falls to GPT-3.5 Turbo levels of performance
|
||||
if run with Ollama's default 2k context window.
|
||||
|
||||
### Sections
|
||||
{: .no_toc }
|
||||
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## Benchmark results
|
||||
|
||||
{: .note :}
|
||||
These are results from single benchmark runs, so expect normal variance of +/- 1-2%.
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
{% include quant-chart.js %}
|
||||
</script>
|
||||
|
||||
<input type="text" id="quantSearchInput" placeholder="Search..." style="width: 100%; max-width: 800px; margin: 10px auto; padding: 8px; display: block; border: 1px solid #ddd; border-radius: 4px;">
|
||||
|
||||
<table style="width: 100%; max-width: 800px; margin: auto; border-collapse: collapse; box-shadow: 0 2px 4px rgba(0,0,0,0.1); font-size: 14px;">
|
||||
<thead style="background-color: #f2f2f2;">
|
||||
<tr>
|
||||
<th style="padding: 8px; text-align: left;">Model</th>
|
||||
<th style="padding: 8px; text-align: center;">Percent completed correctly</th>
|
||||
<th style="padding: 8px; text-align: center;">Percent using correct edit format</th>
|
||||
<th style="padding: 8px; text-align: left;">Command</th>
|
||||
<th style="padding: 8px; text-align: center;">Edit format</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% assign quant_sorted = site.data.quant | sort: 'pass_rate_2' | reverse %}
|
||||
{% for row in quant_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>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<style>
|
||||
tr.selected {
|
||||
color: #0056b3;
|
||||
}
|
||||
table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
td, th {
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
td:nth-child(3), td:nth-child(4) {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.getElementById('quantSearchInput').addEventListener('keyup', function() {
|
||||
var input = this.value.toLowerCase();
|
||||
var rows = document.querySelectorAll('tbody tr');
|
||||
|
||||
rows.forEach(function(row) {
|
||||
var text = row.textContent.toLowerCase();
|
||||
if(text.includes(input)) {
|
||||
row.style.display = '';
|
||||
row.classList.add('selected');
|
||||
} else {
|
||||
row.style.display = 'none';
|
||||
row.classList.remove('selected');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
## Setting Ollama's context window size
|
||||
|
||||
[Ollama uses a 2k context window by default](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-specify-the-context-window-size),
|
||||
which is very small for working with aider.
|
||||
Unlike most other LLM servers, Ollama does not throw an error if you submit
|
||||
a request that exceeds the context window.
|
||||
Instead, it just silently truncates the request by discarding the "oldest" messages
|
||||
in the chat to make it fit within the context window.
|
||||
|
||||
Except for the single 2k context result,
|
||||
all of the Ollama results above were collected with at least an 8k context window.
|
||||
An 8k window is large enough to attempt all the coding problems in the benchmark.
|
||||
Aider sets Ollama's context window to 8k by default, starting in aider v0.65.0.
|
||||
|
||||
You can change the Ollama server's context window with a
|
||||
[`.aider.model.settings.yml` file](https://aider.chat/docs/config/adv-model-settings.html#model-settings)
|
||||
like this:
|
||||
|
||||
```
|
||||
- name: ollama/qwen2.5-coder:32b-instruct-fp16
|
||||
extra_params:
|
||||
num_ctx: 8192
|
||||
```
|
||||
|
||||
## Choosing providers with OpenRouter
|
||||
|
||||
OpenRouter allows you to ignore specific providers in your
|
||||
[preferences](https://openrouter.ai/settings/preferences).
|
||||
This can be used to limit your OpenRouter requests to be
|
||||
served by only your preferred providers.
|
||||
|
||||
## Notes
|
||||
|
||||
This article went through many revisions as I received feedback from
|
||||
numerous members of the community.
|
||||
Here are some of the noteworthy learnings and changes:
|
||||
|
||||
- The first version of this article included incorrect Ollama models.
|
||||
- Earlier Ollama results used the too small default 2k context window,
|
||||
artificially harming the benchmark results.
|
||||
- The benchmark results appear to have uncovered a problem in the way
|
||||
OpenRouter was communicating with Hyperbolic.
|
||||
They fixed the issue 11/24/24, shortly after it was pointed out.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 103 KiB |
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 59 KiB |
BIN
aider/website/assets/quantization.jpg
Normal file
BIN
aider/website/assets/quantization.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 148 KiB |
File diff suppressed because it is too large
Load Diff
@@ -86,9 +86,20 @@
|
||||
## Specify a file with context window and costs for unknown models
|
||||
#model-metadata-file: .aider.model.metadata.json
|
||||
|
||||
## Add a model alias (can be used multiple times)
|
||||
#alias: xxx
|
||||
## Specify multiple values like this:
|
||||
#alias:
|
||||
# - xxx
|
||||
# - yyy
|
||||
# - zzz
|
||||
|
||||
## Verify the SSL cert when connecting to models (default: True)
|
||||
#verify-ssl: true
|
||||
|
||||
## Timeout in seconds for API calls (default: None)
|
||||
#timeout: xxx
|
||||
|
||||
## Specify what edit format the LLM should use (default depends on model)
|
||||
#edit-format: xxx
|
||||
|
||||
@@ -265,14 +276,14 @@
|
||||
## Enable/disable automatic testing after changes (default: False)
|
||||
#auto-test: false
|
||||
|
||||
## Run tests and fix problems found
|
||||
## Run tests, fix problems found and then exit
|
||||
#test: false
|
||||
|
||||
############
|
||||
# Analytics:
|
||||
|
||||
## Enable/disable analytics for one session (default: False)
|
||||
#analytics: false
|
||||
## Enable/disable analytics for current session (default: random)
|
||||
#analytics: xxx
|
||||
|
||||
## Specify a file to log analytics events
|
||||
#analytics-log: xxx
|
||||
@@ -314,6 +325,9 @@
|
||||
## Check for new aider versions on launch
|
||||
#check-update: true
|
||||
|
||||
## Show release notes on first run of new version (default: None, ask user)
|
||||
#show-release-notes: xxx
|
||||
|
||||
## Install the latest version from the main branch
|
||||
#install-main-branch: false
|
||||
|
||||
@@ -365,6 +379,12 @@
|
||||
## Enable/disable fancy input with history and completion (default: True)
|
||||
#fancy-input: true
|
||||
|
||||
## Enable/disable detection and offering to add URLs to chat (default: True)
|
||||
#detect-urls: true
|
||||
|
||||
## Specify which editor to use for the /editor command
|
||||
#editor: xxx
|
||||
|
||||
#################
|
||||
# Voice Settings:
|
||||
|
||||
@@ -373,3 +393,6 @@
|
||||
|
||||
## Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
#voice-language: en
|
||||
|
||||
## Specify the input device name for voice recording
|
||||
#voice-input-device: xxx
|
||||
|
||||
@@ -90,9 +90,15 @@
|
||||
## Specify a file with context window and costs for unknown models
|
||||
#AIDER_MODEL_METADATA_FILE=.aider.model.metadata.json
|
||||
|
||||
## Add a model alias (can be used multiple times)
|
||||
#AIDER_ALIAS=
|
||||
|
||||
## Verify the SSL cert when connecting to models (default: True)
|
||||
#AIDER_VERIFY_SSL=true
|
||||
|
||||
## Timeout in seconds for API calls (default: None)
|
||||
#AIDER_TIMEOUT=
|
||||
|
||||
## Specify what edit format the LLM should use (default depends on model)
|
||||
#AIDER_EDIT_FORMAT=
|
||||
|
||||
@@ -264,14 +270,14 @@
|
||||
## Enable/disable automatic testing after changes (default: False)
|
||||
#AIDER_AUTO_TEST=false
|
||||
|
||||
## Run tests and fix problems found
|
||||
## Run tests, fix problems found and then exit
|
||||
#AIDER_TEST=false
|
||||
|
||||
############
|
||||
# Analytics:
|
||||
|
||||
## Enable/disable analytics for one session (default: False)
|
||||
#AIDER_ANALYTICS=false
|
||||
## Enable/disable analytics for current session (default: random)
|
||||
#AIDER_ANALYTICS=
|
||||
|
||||
## Specify a file to log analytics events
|
||||
#AIDER_ANALYTICS_LOG=
|
||||
@@ -300,6 +306,9 @@
|
||||
## Check for new aider versions on launch
|
||||
#AIDER_CHECK_UPDATE=true
|
||||
|
||||
## Show release notes on first run of new version (default: None, ask user)
|
||||
#AIDER_SHOW_RELEASE_NOTES=
|
||||
|
||||
## Install the latest version from the main branch
|
||||
#AIDER_INSTALL_MAIN_BRANCH=false
|
||||
|
||||
@@ -348,6 +357,12 @@
|
||||
## Enable/disable fancy input with history and completion (default: True)
|
||||
#AIDER_FANCY_INPUT=true
|
||||
|
||||
## Enable/disable detection and offering to add URLs to chat (default: True)
|
||||
#AIDER_DETECT_URLS=true
|
||||
|
||||
## Specify which editor to use for the /editor command
|
||||
#AIDER_EDITOR=
|
||||
|
||||
#################
|
||||
# Voice Settings:
|
||||
|
||||
@@ -356,3 +371,6 @@
|
||||
|
||||
## Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
#AIDER_VOICE_LANGUAGE=en
|
||||
|
||||
## Specify the input device name for voice recording
|
||||
#AIDER_VOICE_INPUT_DEVICE=
|
||||
|
||||
@@ -11,6 +11,13 @@ description: Configuring advanced settings for LLMs.
|
||||
In most cases, you can safely ignore aider's warning about unknown context
|
||||
window size and model costs.
|
||||
|
||||
{: .note }
|
||||
Aider never *enforces* token limits, it only *reports* token limit errors
|
||||
from the API provider.
|
||||
You probably don't need to
|
||||
configure aider with the proper token limits
|
||||
for unusual models.
|
||||
|
||||
But, you can register context window limits and costs for models that aren't known
|
||||
to aider. Create a `.aider.model.metadata.json` file in one of these locations:
|
||||
|
||||
@@ -55,8 +62,10 @@ These model settings are pre-configured for most popular models.
|
||||
But it can sometimes be helpful to override them or add settings for
|
||||
a model that aider doesn't know about.
|
||||
|
||||
To do that,
|
||||
create a `.aider.model.settings.yml` file in one of these locations:
|
||||
|
||||
### Configuration file locations
|
||||
|
||||
You can override or add settings for any model by creating a `.aider.model.settings.yml` file in one of these locations:
|
||||
|
||||
- Your home directory.
|
||||
- The root if your git repo.
|
||||
@@ -66,9 +75,31 @@ create a `.aider.model.settings.yml` file in one of these locations:
|
||||
If the files above exist, they will be loaded in that order.
|
||||
Files loaded last will take priority.
|
||||
|
||||
The yaml file should be a a list of dictionary objects for each model.
|
||||
For example, below are all the pre-configured model settings
|
||||
to give a sense for the settings which are supported.
|
||||
The yaml file should be a list of dictionary objects for each model.
|
||||
|
||||
|
||||
### Global extra params
|
||||
|
||||
You can use the special model name `aider/extra_params` to define
|
||||
`extra_params` that will be passed to `litellm.completion()` for all models.
|
||||
Only the `extra_params` dict is used from this special model name.
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
- name: aider/extra_params
|
||||
extra_params:
|
||||
extra_headers:
|
||||
Custom-Header: value
|
||||
max_tokens: 8192
|
||||
```
|
||||
|
||||
These settings will be merged with any model-specific settings, with the
|
||||
`aider/extra_params` settings taking precedence for any direct conflicts.
|
||||
|
||||
### Example model settings
|
||||
|
||||
Below are all the pre-configured model settings to give a sense for the settings which are supported.
|
||||
|
||||
You can also look at the `ModelSettings` class in
|
||||
[models.py](https://github.com/Aider-AI/aider/blob/main/aider/models.py)
|
||||
@@ -241,6 +272,38 @@ cog.out("```\n")
|
||||
use_system_prompt: true
|
||||
use_temperature: true
|
||||
weak_model_name: gpt-4o-mini
|
||||
- cache_control: false
|
||||
caches_by_default: false
|
||||
edit_format: diff
|
||||
editor_edit_format: null
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: gpt-4o-2024-11-20
|
||||
reminder: sys
|
||||
send_undo_reply: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: true
|
||||
use_temperature: true
|
||||
weak_model_name: gpt-4o-mini
|
||||
- cache_control: false
|
||||
caches_by_default: false
|
||||
edit_format: diff
|
||||
editor_edit_format: null
|
||||
editor_model_name: null
|
||||
examples_as_sys_msg: false
|
||||
extra_params: null
|
||||
lazy: true
|
||||
name: openai/gpt-4o-2024-11-20
|
||||
reminder: sys
|
||||
send_undo_reply: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: true
|
||||
use_temperature: true
|
||||
weak_model_name: gpt-4o-mini
|
||||
- cache_control: false
|
||||
caches_by_default: false
|
||||
edit_format: diff
|
||||
@@ -441,7 +504,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
max_tokens: 8192
|
||||
lazy: false
|
||||
name: claude-3-5-sonnet-20240620
|
||||
@@ -460,7 +523,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
max_tokens: 8192
|
||||
lazy: false
|
||||
name: anthropic/claude-3-5-sonnet-20240620
|
||||
@@ -479,7 +542,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
max_tokens: 8192
|
||||
lazy: false
|
||||
name: anthropic/claude-3-5-sonnet-20241022
|
||||
@@ -498,7 +561,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
max_tokens: 8192
|
||||
lazy: false
|
||||
name: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0
|
||||
@@ -517,7 +580,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
max_tokens: 8192
|
||||
lazy: false
|
||||
name: anthropic/claude-3-5-sonnet-latest
|
||||
@@ -536,7 +599,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
max_tokens: 8192
|
||||
lazy: false
|
||||
name: claude-3-5-sonnet-20241022
|
||||
@@ -555,7 +618,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
lazy: false
|
||||
name: anthropic/claude-3-haiku-20240307
|
||||
reminder: user
|
||||
@@ -573,7 +636,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: false
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
lazy: false
|
||||
name: anthropic/claude-3-5-haiku-20241022
|
||||
reminder: user
|
||||
@@ -591,7 +654,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: false
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
lazy: false
|
||||
name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
|
||||
reminder: user
|
||||
@@ -609,7 +672,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
lazy: false
|
||||
name: claude-3-5-haiku-20241022
|
||||
reminder: user
|
||||
@@ -644,7 +707,7 @@ cog.out("```\n")
|
||||
examples_as_sys_msg: true
|
||||
extra_params:
|
||||
extra_headers:
|
||||
anthropic-beta: prompt-caching-2024-07-31
|
||||
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
|
||||
lazy: false
|
||||
name: claude-3-haiku-20240307
|
||||
reminder: user
|
||||
@@ -1057,7 +1120,7 @@ cog.out("```\n")
|
||||
name: openai/o1-mini
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1073,7 +1136,7 @@ cog.out("```\n")
|
||||
name: azure/o1-mini
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1089,7 +1152,7 @@ cog.out("```\n")
|
||||
name: o1-mini
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1105,7 +1168,7 @@ cog.out("```\n")
|
||||
name: openai/o1-preview
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1121,7 +1184,7 @@ cog.out("```\n")
|
||||
name: azure/o1-preview
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
@@ -1137,7 +1200,7 @@ cog.out("```\n")
|
||||
name: o1-preview
|
||||
reminder: user
|
||||
send_undo_reply: false
|
||||
streaming: false
|
||||
streaming: true
|
||||
use_repo_map: true
|
||||
use_system_prompt: false
|
||||
use_temperature: false
|
||||
|
||||
@@ -142,9 +142,20 @@ cog.outl("```")
|
||||
## Specify a file with context window and costs for unknown models
|
||||
#model-metadata-file: .aider.model.metadata.json
|
||||
|
||||
## Add a model alias (can be used multiple times)
|
||||
#alias: xxx
|
||||
## Specify multiple values like this:
|
||||
#alias:
|
||||
# - xxx
|
||||
# - yyy
|
||||
# - zzz
|
||||
|
||||
## Verify the SSL cert when connecting to models (default: True)
|
||||
#verify-ssl: true
|
||||
|
||||
## Timeout in seconds for API calls (default: None)
|
||||
#timeout: xxx
|
||||
|
||||
## Specify what edit format the LLM should use (default depends on model)
|
||||
#edit-format: xxx
|
||||
|
||||
@@ -321,14 +332,14 @@ cog.outl("```")
|
||||
## Enable/disable automatic testing after changes (default: False)
|
||||
#auto-test: false
|
||||
|
||||
## Run tests and fix problems found
|
||||
## Run tests, fix problems found and then exit
|
||||
#test: false
|
||||
|
||||
############
|
||||
# Analytics:
|
||||
|
||||
## Enable/disable analytics for one session (default: False)
|
||||
#analytics: false
|
||||
## Enable/disable analytics for current session (default: random)
|
||||
#analytics: xxx
|
||||
|
||||
## Specify a file to log analytics events
|
||||
#analytics-log: xxx
|
||||
@@ -370,6 +381,9 @@ cog.outl("```")
|
||||
## Check for new aider versions on launch
|
||||
#check-update: true
|
||||
|
||||
## Show release notes on first run of new version (default: None, ask user)
|
||||
#show-release-notes: xxx
|
||||
|
||||
## Install the latest version from the main branch
|
||||
#install-main-branch: false
|
||||
|
||||
@@ -421,6 +435,12 @@ cog.outl("```")
|
||||
## Enable/disable fancy input with history and completion (default: True)
|
||||
#fancy-input: true
|
||||
|
||||
## Enable/disable detection and offering to add URLs to chat (default: True)
|
||||
#detect-urls: true
|
||||
|
||||
## Specify which editor to use for the /editor command
|
||||
#editor: xxx
|
||||
|
||||
#################
|
||||
# Voice Settings:
|
||||
|
||||
@@ -429,5 +449,8 @@ cog.outl("```")
|
||||
|
||||
## Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
#voice-language: en
|
||||
|
||||
## Specify the input device name for voice recording
|
||||
#voice-input-device: xxx
|
||||
```
|
||||
<!--[[[end]]]-->
|
||||
|
||||
@@ -132,9 +132,15 @@ cog.outl("```")
|
||||
## Specify a file with context window and costs for unknown models
|
||||
#AIDER_MODEL_METADATA_FILE=.aider.model.metadata.json
|
||||
|
||||
## Add a model alias (can be used multiple times)
|
||||
#AIDER_ALIAS=
|
||||
|
||||
## Verify the SSL cert when connecting to models (default: True)
|
||||
#AIDER_VERIFY_SSL=true
|
||||
|
||||
## Timeout in seconds for API calls (default: None)
|
||||
#AIDER_TIMEOUT=
|
||||
|
||||
## Specify what edit format the LLM should use (default depends on model)
|
||||
#AIDER_EDIT_FORMAT=
|
||||
|
||||
@@ -306,14 +312,14 @@ cog.outl("```")
|
||||
## Enable/disable automatic testing after changes (default: False)
|
||||
#AIDER_AUTO_TEST=false
|
||||
|
||||
## Run tests and fix problems found
|
||||
## Run tests, fix problems found and then exit
|
||||
#AIDER_TEST=false
|
||||
|
||||
############
|
||||
# Analytics:
|
||||
|
||||
## Enable/disable analytics for one session (default: False)
|
||||
#AIDER_ANALYTICS=false
|
||||
## Enable/disable analytics for current session (default: random)
|
||||
#AIDER_ANALYTICS=
|
||||
|
||||
## Specify a file to log analytics events
|
||||
#AIDER_ANALYTICS_LOG=
|
||||
@@ -342,6 +348,9 @@ cog.outl("```")
|
||||
## Check for new aider versions on launch
|
||||
#AIDER_CHECK_UPDATE=true
|
||||
|
||||
## Show release notes on first run of new version (default: None, ask user)
|
||||
#AIDER_SHOW_RELEASE_NOTES=
|
||||
|
||||
## Install the latest version from the main branch
|
||||
#AIDER_INSTALL_MAIN_BRANCH=false
|
||||
|
||||
@@ -390,6 +399,12 @@ cog.outl("```")
|
||||
## Enable/disable fancy input with history and completion (default: True)
|
||||
#AIDER_FANCY_INPUT=true
|
||||
|
||||
## Enable/disable detection and offering to add URLs to chat (default: True)
|
||||
#AIDER_DETECT_URLS=true
|
||||
|
||||
## Specify which editor to use for the /editor command
|
||||
#AIDER_EDITOR=
|
||||
|
||||
#################
|
||||
# Voice Settings:
|
||||
|
||||
@@ -398,7 +413,8 @@ cog.outl("```")
|
||||
|
||||
## Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
#AIDER_VOICE_LANGUAGE=en
|
||||
|
||||
## Specify the input device name for voice recording
|
||||
#AIDER_VOICE_INPUT_DEVICE=
|
||||
```
|
||||
<!--[[[end]]]-->
|
||||
|
||||
|
||||
|
||||
127
aider/website/docs/config/editor.md
Normal file
127
aider/website/docs/config/editor.md
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
parent: Configuration
|
||||
nav_order: 15
|
||||
description: How to configure a custom editor for aider's /editor command
|
||||
---
|
||||
|
||||
# Editor configuration
|
||||
|
||||
Aider allows you to configure your preferred text editor for use with the `/editor` command. The editor must be capable of running in "blocking mode", meaning the command line will wait until you close the editor before proceeding.
|
||||
|
||||
## Using `--editor`
|
||||
|
||||
You can specify the text editor with the `--editor` switch or using
|
||||
`editor:` in aider's
|
||||
[yaml config file](https://aider.chat/docs/config/aider_conf.html).
|
||||
|
||||
## Environment variables
|
||||
|
||||
Aider checks the following environment variables in order to determine which editor to use:
|
||||
|
||||
1. `AIDER_EDITOR`
|
||||
2. `VISUAL`
|
||||
3. `EDITOR`
|
||||
|
||||
## Default behavior
|
||||
|
||||
If no editor is configured, aider will use these platform-specific defaults:
|
||||
|
||||
- Windows: `notepad`
|
||||
- macOS: `vim`
|
||||
- Linux/Unix: `vi`
|
||||
|
||||
## Using a custom editor
|
||||
|
||||
You can set your preferred editor in your shell's configuration file (e.g., `.bashrc`, `.zshrc`):
|
||||
|
||||
```bash
|
||||
export AIDER_EDITOR=vim
|
||||
```
|
||||
|
||||
## Popular Editors by Platform
|
||||
|
||||
### macOS
|
||||
|
||||
1. **vim**
|
||||
```bash
|
||||
export AIDER_EDITOR=vim
|
||||
```
|
||||
|
||||
2. **Emacs**
|
||||
```bash
|
||||
export AIDER_EDITOR=emacs
|
||||
```
|
||||
|
||||
3. **VSCode**
|
||||
```bash
|
||||
export AIDER_EDITOR="code --wait"
|
||||
```
|
||||
|
||||
4. **Sublime Text**
|
||||
```bash
|
||||
export AIDER_EDITOR="subl --wait"
|
||||
```
|
||||
|
||||
5. **BBEdit**
|
||||
```bash
|
||||
export AIDER_EDITOR="bbedit --wait"
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
1. **vim**
|
||||
```bash
|
||||
export AIDER_EDITOR=vim
|
||||
```
|
||||
|
||||
2. **Emacs**
|
||||
```bash
|
||||
export AIDER_EDITOR=emacs
|
||||
```
|
||||
|
||||
3. **nano**
|
||||
```bash
|
||||
export AIDER_EDITOR=nano
|
||||
```
|
||||
|
||||
4. **VSCode**
|
||||
```bash
|
||||
export AIDER_EDITOR="code --wait"
|
||||
```
|
||||
|
||||
5. **Sublime Text**
|
||||
```bash
|
||||
export AIDER_EDITOR="subl --wait"
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
1. **Notepad**
|
||||
```bat
|
||||
set AIDER_EDITOR=notepad
|
||||
```
|
||||
|
||||
2. **VSCode**
|
||||
```bat
|
||||
set AIDER_EDITOR="code --wait"
|
||||
```
|
||||
|
||||
3. **Notepad++**
|
||||
```bat
|
||||
set AIDER_EDITOR="notepad++ -multiInst -notabbar -nosession -noPlugin -waitForClose"
|
||||
```
|
||||
|
||||
## Editor command arguments
|
||||
|
||||
Some editors require specific command-line arguments to operate in blocking mode. The `--wait` flag (or equivalent) is commonly used to make the editor block until the file is closed.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter issues with your editor not blocking (returning to the prompt immediately), verify that:
|
||||
|
||||
1. Your editor supports blocking mode
|
||||
2. You've included the necessary command-line arguments for blocking mode
|
||||
3. The editor command is properly quoted if it contains spaces or special characters, e.g.:
|
||||
```bash
|
||||
export AIDER_EDITOR="code --wait"
|
||||
```
|
||||
72
aider/website/docs/config/model-aliases.md
Normal file
72
aider/website/docs/config/model-aliases.md
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
parent: Configuration
|
||||
nav_order: 1000
|
||||
description: Assign convenient short names to models.
|
||||
---
|
||||
|
||||
# Model Aliases
|
||||
|
||||
Model aliases allow you to create shorthand names for models you frequently use. This is particularly useful for models with long names or when you want to standardize model usage across your team.
|
||||
|
||||
## Command Line Usage
|
||||
|
||||
You can define aliases when launching aider using the `--alias` option:
|
||||
|
||||
```bash
|
||||
aider --alias "fast:gpt-3.5-turbo" --alias "smart:gpt-4"
|
||||
```
|
||||
|
||||
Multiple aliases can be defined by using the `--alias` option multiple times. Each alias definition should be in the format `alias:model-name`.
|
||||
|
||||
## Configuration File
|
||||
|
||||
You can also define aliases in your [`.aider.conf.yml` file](https://aider.chat/docs/config/aider_conf.html):
|
||||
|
||||
```yaml
|
||||
alias:
|
||||
- "fast:gpt-3.5-turbo"
|
||||
- "smart:gpt-4"
|
||||
- "hacker:claude-3-sonnet-20240229"
|
||||
```
|
||||
|
||||
## Using Aliases
|
||||
|
||||
Once defined, you can use the alias instead of the full model name:
|
||||
|
||||
```bash
|
||||
aider --model fast # Uses gpt-3.5-turbo
|
||||
aider --model smart # Uses gpt-4
|
||||
```
|
||||
|
||||
## Built-in Aliases
|
||||
|
||||
Aider includes some built-in aliases for convenience:
|
||||
|
||||
<!--[[[cog
|
||||
import cog
|
||||
from aider.models import MODEL_ALIASES
|
||||
|
||||
for alias, model in sorted(MODEL_ALIASES.items()):
|
||||
cog.outl(f"- `{alias}`: {model}")
|
||||
]]]-->
|
||||
- `3`: gpt-3.5-turbo
|
||||
- `35-turbo`: gpt-3.5-turbo
|
||||
- `35turbo`: gpt-3.5-turbo
|
||||
- `4`: gpt-4-0613
|
||||
- `4-turbo`: gpt-4-1106-preview
|
||||
- `4o`: gpt-4o-2024-08-06
|
||||
- `deepseek`: deepseek/deepseek-coder
|
||||
- `haiku`: claude-3-5-haiku-20241022
|
||||
- `opus`: claude-3-opus-20240229
|
||||
- `sonnet`: claude-3-5-sonnet-20241022
|
||||
<!--[[[end]]]-->
|
||||
|
||||
## Priority
|
||||
|
||||
If the same alias is defined in multiple places, the priority is:
|
||||
|
||||
1. Command line aliases (highest priority)
|
||||
2. Configuration file aliases
|
||||
3. Built-in aliases (lowest priority)
|
||||
|
||||
This allows you to override built-in aliases with your own preferences.
|
||||
@@ -32,9 +32,9 @@ usage: aider [-h] [--openai-api-key] [--anthropic-api-key] [--model]
|
||||
[--openai-api-type] [--openai-api-version]
|
||||
[--openai-api-deployment-id] [--openai-organization-id]
|
||||
[--model-settings-file] [--model-metadata-file]
|
||||
[--verify-ssl | --no-verify-ssl] [--edit-format]
|
||||
[--architect] [--weak-model] [--editor-model]
|
||||
[--editor-edit-format]
|
||||
[--alias] [--verify-ssl | --no-verify-ssl] [--timeout]
|
||||
[--edit-format] [--architect] [--weak-model]
|
||||
[--editor-model] [--editor-edit-format]
|
||||
[--show-model-warnings | --no-show-model-warnings]
|
||||
[--max-chat-history-tokens] [--env-file]
|
||||
[--cache-prompts | --no-cache-prompts]
|
||||
@@ -66,14 +66,17 @@ usage: aider [-h] [--openai-api-key] [--anthropic-api-key] [--model]
|
||||
[--analytics-disable] [--file] [--read] [--vim]
|
||||
[--chat-language] [--version] [--just-check-update]
|
||||
[--check-update | --no-check-update]
|
||||
[--show-release-notes | --no-show-release-notes]
|
||||
[--install-main-branch] [--upgrade] [--apply]
|
||||
[--apply-clipboard-edits] [--yes-always] [-v]
|
||||
[--show-repo-map] [--show-prompts] [--exit] [--message]
|
||||
[--message-file] [--load] [--encoding] [-c]
|
||||
[--gui | --no-gui | --browser | --no-browser]
|
||||
[--suggest-shell-commands | --no-suggest-shell-commands]
|
||||
[--fancy-input | --no-fancy-input] [--voice-format]
|
||||
[--voice-language]
|
||||
[--fancy-input | --no-fancy-input]
|
||||
[--detect-urls | --no-detect-urls] [--editor]
|
||||
[--voice-format] [--voice-language]
|
||||
[--voice-input-device]
|
||||
|
||||
```
|
||||
|
||||
@@ -190,6 +193,10 @@ Specify a file with context window and costs for unknown models
|
||||
Default: .aider.model.metadata.json
|
||||
Environment variable: `AIDER_MODEL_METADATA_FILE`
|
||||
|
||||
### `--alias ALIAS:MODEL`
|
||||
Add a model alias (can be used multiple times)
|
||||
Environment variable: `AIDER_ALIAS`
|
||||
|
||||
### `--verify-ssl`
|
||||
Verify the SSL cert when connecting to models (default: True)
|
||||
Default: True
|
||||
@@ -198,6 +205,10 @@ Aliases:
|
||||
- `--verify-ssl`
|
||||
- `--no-verify-ssl`
|
||||
|
||||
### `--timeout VALUE`
|
||||
Timeout in seconds for API calls (default: None)
|
||||
Environment variable: `AIDER_TIMEOUT`
|
||||
|
||||
### `--edit-format EDIT_FORMAT`
|
||||
Specify what edit format the LLM should use (default depends on model)
|
||||
Environment variable: `AIDER_EDIT_FORMAT`
|
||||
@@ -503,15 +514,14 @@ Aliases:
|
||||
- `--no-auto-test`
|
||||
|
||||
### `--test`
|
||||
Run tests and fix problems found
|
||||
Run tests, fix problems found and then exit
|
||||
Default: False
|
||||
Environment variable: `AIDER_TEST`
|
||||
|
||||
## Analytics:
|
||||
|
||||
### `--analytics`
|
||||
Enable/disable analytics for one session (default: False)
|
||||
Default: False
|
||||
Enable/disable analytics for current session (default: random)
|
||||
Environment variable: `AIDER_ANALYTICS`
|
||||
Aliases:
|
||||
- `--analytics`
|
||||
@@ -561,6 +571,13 @@ Aliases:
|
||||
- `--check-update`
|
||||
- `--no-check-update`
|
||||
|
||||
### `--show-release-notes`
|
||||
Show release notes on first run of new version (default: None, ask user)
|
||||
Environment variable: `AIDER_SHOW_RELEASE_NOTES`
|
||||
Aliases:
|
||||
- `--show-release-notes`
|
||||
- `--no-show-release-notes`
|
||||
|
||||
### `--install-main-branch`
|
||||
Install the latest version from the main branch
|
||||
Default: False
|
||||
@@ -666,6 +683,18 @@ Aliases:
|
||||
- `--fancy-input`
|
||||
- `--no-fancy-input`
|
||||
|
||||
### `--detect-urls`
|
||||
Enable/disable detection and offering to add URLs to chat (default: True)
|
||||
Default: True
|
||||
Environment variable: `AIDER_DETECT_URLS`
|
||||
Aliases:
|
||||
- `--detect-urls`
|
||||
- `--no-detect-urls`
|
||||
|
||||
### `--editor VALUE`
|
||||
Specify which editor to use for the /editor command
|
||||
Environment variable: `AIDER_EDITOR`
|
||||
|
||||
## Voice Settings:
|
||||
|
||||
### `--voice-format VOICE_FORMAT`
|
||||
@@ -677,4 +706,8 @@ Environment variable: `AIDER_VOICE_FORMAT`
|
||||
Specify the language for voice using ISO 639-1 code (default: auto)
|
||||
Default: en
|
||||
Environment variable: `AIDER_VOICE_LANGUAGE`
|
||||
|
||||
### `--voice-input-device VOICE_INPUT_DEVICE`
|
||||
Specify the input device name for voice recording
|
||||
Environment variable: `AIDER_VOICE_INPUT_DEVICE`
|
||||
<!--[[[end]]]-->
|
||||
|
||||
@@ -60,6 +60,23 @@ directory you start in.
|
||||
You can also create a `.aiderignore` file to tell aider
|
||||
to ignore parts of the repo that aren't relevant to your task.
|
||||
This file conforms to `.gitignore` syntax and conventions.
|
||||
For example, to focus only on specific directories in a monorepo,
|
||||
you could create a `.aiderignore` file with:
|
||||
|
||||
```
|
||||
# Ignore everything
|
||||
/*
|
||||
|
||||
# Allow specific directories and their contents
|
||||
!foo/
|
||||
!bar/
|
||||
!baz/
|
||||
|
||||
# Allow nested files under these directories
|
||||
!foo/**
|
||||
!bar/**
|
||||
!baz/**
|
||||
```
|
||||
|
||||
You can use `--aiderignore <filename>` to name a specific file
|
||||
to use for ignore patterns.
|
||||
@@ -150,10 +167,12 @@ python -m aider
|
||||
|
||||
|
||||
|
||||
|
||||
## Can I change the system prompts that aider uses?
|
||||
|
||||
Aider is set up to support different system prompts and edit formats
|
||||
The most convenient way to add custom instructions is to use a
|
||||
[conventions file](https://aider.chat/docs/usage/conventions.html).
|
||||
|
||||
But, aider is set up to support different actual system prompts and edit formats
|
||||
in a modular way. If you look in the `aider/coders` subdirectory, you'll
|
||||
see there's a base coder with base prompts, and then there are
|
||||
a number of
|
||||
@@ -191,6 +210,28 @@ You can also refer to the
|
||||
[instructions for installing a development version of aider](https://aider.chat/docs/install/optional.html#install-the-development-version-of-aider).
|
||||
|
||||
|
||||
## How are the "aider wrote xx% of code" stats computed?
|
||||
|
||||
[Aider is tightly integrated with git](/docs/git.html) so all
|
||||
of aider's code changes are committed to the repo with proper attribution.
|
||||
The
|
||||
[stats are computed](https://github.com/Aider-AI/aider/blob/main/scripts/blame.py)
|
||||
by doing something like `git blame` on the repo,
|
||||
and counting up who wrote all the new lines of code in each release.
|
||||
Only lines in source code files are counted, not documentation or prompt files.
|
||||
|
||||
## Why is the LLM speaking to me in an unexpected language?
|
||||
|
||||
Aider goes to some effort to prompt the model to use the language that is configured
|
||||
for your system.
|
||||
But LLMs aren't fully reliable, and they sometimes decide to speak in
|
||||
an unexpected language.
|
||||
Claude is especially fond of speaking French.
|
||||
|
||||
You can explicitly set the language that aider tells the model to use with
|
||||
`--chat-language <language>`.
|
||||
But the LLM may not comply.
|
||||
|
||||
## Can I share my aider chat transcript?
|
||||
|
||||
Yes, you can now share aider chat logs in a pretty way.
|
||||
@@ -213,6 +254,15 @@ This will give you a URL like this, which shows the chat history like you'd see
|
||||
https://aider.chat/share/?mdurl=https://gist.github.com/Aider-AI/2087ab8b64034a078c0a209440ac8be0
|
||||
```
|
||||
|
||||
## Can I edit files myself while aider is running?
|
||||
|
||||
Yes. Aider always reads the latest copy of files from the file
|
||||
system when you send each message.
|
||||
|
||||
While you're waiting for aider's reply to complete, it's probably unwise to
|
||||
edit files that you've added to the chat.
|
||||
Your edits and aider's edits might conflict.
|
||||
|
||||
## What is Aider AI LLC?
|
||||
|
||||
Aider AI LLC is the company behind the aider AI coding tool.
|
||||
@@ -222,11 +272,5 @@ under an
|
||||
[Apache 2.0 license](https://github.com/Aider-AI/aider/blob/main/LICENSE.txt).
|
||||
|
||||
|
||||
## Can I edit files myself while aider is running?
|
||||
<div style="height:80vh"></div>
|
||||
|
||||
Yes. Aider always reads the latest copy of files from the file
|
||||
system when you send each message.
|
||||
|
||||
While you're waiting for aider's reply to complete, it's probably unwise to
|
||||
edit files that you've added to the chat.
|
||||
Your edits and aider's edits might conflict.
|
||||
|
||||
@@ -53,6 +53,7 @@ Installing PortAudio is completely optional, but can usually be accomplished lik
|
||||
- For Windows, there is no need to install PortAudio.
|
||||
- For Mac, do `brew install portaudio`
|
||||
- For Linux, do `sudo apt-get install libportaudio2`
|
||||
- Some linux environments may also need `sudo apt install libasound2-plugins`
|
||||
|
||||
## Add aider to your editor
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ This measures the LLM's coding ability, and whether it can
|
||||
write new code that integrates into existing code.
|
||||
The model also has to successfully apply all its changes to the source file without human intervention.
|
||||
|
||||
<input type="text" id="editSearchInput" placeholder="Search..." style="width: 100%; max-width: 800px; margin: 10px auto; padding: 8px; display: block; border: 1px solid #ddd; border-radius: 4px;">
|
||||
|
||||
<table style="width: 100%; max-width: 800px; margin: auto; border-collapse: collapse; box-shadow: 0 2px 4px rgba(0,0,0,0.1); font-size: 14px;">
|
||||
<thead style="background-color: #f2f2f2;">
|
||||
<tr>
|
||||
@@ -58,81 +60,7 @@ The model also has to successfully apply all its changes to the source file with
|
||||
<canvas id="editChart" width="800" height="450" style="margin-top: 20px"></canvas>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('editChart').getContext('2d');
|
||||
const HIGHTLIGHT_MODEL = 'no no no no';
|
||||
var leaderboardData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: [],
|
||||
backgroundColor: function(context) {
|
||||
const label = context.chart.data.labels[context.dataIndex] || '';
|
||||
return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 0.2)' : 'rgba(54, 162, 235, 0.2)';
|
||||
},
|
||||
borderColor: function(context) {
|
||||
const label = context.chart.data.labels[context.dataIndex] || '';
|
||||
return (label && label.includes(HIGHTLIGHT_MODEL)) ? 'rgba(255, 99, 132, 1)' : 'rgba(54, 162, 235, 1)';
|
||||
},
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
|
||||
var allData = [];
|
||||
{% for row in edit_sorted %}
|
||||
allData.push({
|
||||
model: '{{ row.model }}',
|
||||
pass_rate_2: {{ row.pass_rate_2 }},
|
||||
percent_cases_well_formed: {{ row.percent_cases_well_formed }}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
function updateChart() {
|
||||
var selectedRows = document.querySelectorAll('tr.selected');
|
||||
var showAll = selectedRows.length === 0;
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
allData.forEach(function(row, index) {
|
||||
var rowElement = document.getElementById('edit-row-' + index);
|
||||
if (showAll) {
|
||||
rowElement.classList.remove('selected');
|
||||
}
|
||||
if (showAll || rowElement.classList.contains('selected')) {
|
||||
leaderboardData.labels.push(row.model);
|
||||
leaderboardData.datasets[0].data.push(row.pass_rate_2);
|
||||
}
|
||||
});
|
||||
|
||||
leaderboardChart.update();
|
||||
}
|
||||
|
||||
var tableBody = document.querySelector('table tbody');
|
||||
allData.forEach(function(row, index) {
|
||||
var tr = tableBody.children[index];
|
||||
tr.id = 'edit-row-' + index;
|
||||
tr.style.cursor = 'pointer';
|
||||
tr.onclick = function() {
|
||||
this.classList.toggle('selected');
|
||||
updateChart();
|
||||
};
|
||||
});
|
||||
|
||||
var leaderboardChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: leaderboardData,
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
});
|
||||
{% include edit-leaderboard.js %}
|
||||
</script>
|
||||
<style>
|
||||
tr.selected {
|
||||
@@ -158,6 +86,8 @@ The refactoring benchmark requires a large context window to
|
||||
work with large source files.
|
||||
Therefore, results are available for fewer models.
|
||||
|
||||
<input type="text" id="refacSearchInput" placeholder="Search..." style="width: 100%; max-width: 800px; margin: 10px auto; padding: 8px; display: block; border: 1px solid #ddd; border-radius: 4px;">
|
||||
|
||||
<table style="width: 100%; max-width: 800px; margin: auto; border-collapse: collapse; box-shadow: 0 2px 4px rgba(0,0,0,0.1); font-size: 14px;">
|
||||
<thead style="background-color: #f2f2f2;">
|
||||
<tr>
|
||||
@@ -185,74 +115,7 @@ Therefore, results are available for fewer models.
|
||||
<canvas id="refacChart" width="800" height="450" style="margin-top: 20px"></canvas>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var ctx = document.getElementById('refacChart').getContext('2d');
|
||||
var leaderboardData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Percent completed correctly',
|
||||
data: [],
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
|
||||
var allData = [];
|
||||
{% for row in refac_sorted %}
|
||||
allData.push({
|
||||
model: '{{ row.model }}',
|
||||
pass_rate_1: {{ row.pass_rate_1 }},
|
||||
percent_cases_well_formed: {{ row.percent_cases_well_formed }}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
function updateChart() {
|
||||
var selectedRows = document.querySelectorAll('tr.selected');
|
||||
var showAll = selectedRows.length === 0;
|
||||
|
||||
leaderboardData.labels = [];
|
||||
leaderboardData.datasets[0].data = [];
|
||||
|
||||
allData.forEach(function(row, index) {
|
||||
var rowElement = document.getElementById('refac-row-' + index);
|
||||
if (showAll) {
|
||||
rowElement.classList.remove('selected');
|
||||
}
|
||||
if (showAll || rowElement.classList.contains('selected')) {
|
||||
leaderboardData.labels.push(row.model);
|
||||
leaderboardData.datasets[0].data.push(row.pass_rate_1);
|
||||
}
|
||||
});
|
||||
|
||||
leaderboardChart.update();
|
||||
}
|
||||
|
||||
var tableBody = document.querySelectorAll('table tbody')[1];
|
||||
allData.forEach(function(row, index) {
|
||||
var tr = tableBody.children[index];
|
||||
tr.id = 'refac-row-' + index;
|
||||
tr.style.cursor = 'pointer';
|
||||
tr.onclick = function() {
|
||||
this.classList.toggle('selected');
|
||||
updateChart();
|
||||
};
|
||||
});
|
||||
|
||||
var leaderboardChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: leaderboardData,
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChart();
|
||||
});
|
||||
{% include refactor-leaderboard.js %}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -318,6 +181,6 @@ mod_dates = [get_last_modified_date(file) for file in files]
|
||||
latest_mod_date = max(mod_dates)
|
||||
cog.out(f"{latest_mod_date.strftime('%B %d, %Y.')}")
|
||||
]]]-->
|
||||
November 11, 2024.
|
||||
November 28, 2024.
|
||||
<!--[[[end]]]-->
|
||||
</p>
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
parent: Connecting to LLMs
|
||||
nav_order: 850
|
||||
---
|
||||
|
||||
# Editing format
|
||||
|
||||
Aider uses different "edit formats" to collect code edits from different LLMs.
|
||||
The "whole" format is the easiest for an LLM to use, but it uses a lot of tokens
|
||||
and may limit how large a file can be edited.
|
||||
Models which can use one of the diff formats are much more efficient,
|
||||
using far fewer tokens.
|
||||
Models that use a diff-like format are able to
|
||||
edit larger files with less cost and without hitting token limits.
|
||||
|
||||
Aider is configured to use the best edit format for the popular OpenAI and Anthropic models
|
||||
and the [other models recommended on the LLM page](https://aider.chat/docs/llms.html).
|
||||
For lesser known models aider will default to using the "whole" editing format
|
||||
since it is the easiest format for an LLM to use.
|
||||
|
||||
If you would like to experiment with the more advanced formats, you can
|
||||
use these switches: `--edit-format diff` or `--edit-format udiff`.
|
||||
26
aider/website/docs/llms/lm-studio.md
Normal file
26
aider/website/docs/llms/lm-studio.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
parent: Connecting to LLMs
|
||||
nav_order: 400
|
||||
---
|
||||
|
||||
# LM Studio
|
||||
|
||||
To use LM Studio:
|
||||
|
||||
```
|
||||
python -m pip install -U aider-chat
|
||||
|
||||
export LM_STUDIO_API_KEY=<key> # Mac/Linux
|
||||
setx LM_STUDIO_API_KEY <key> # Windows, restart shell after setx
|
||||
|
||||
export LM_STUDIO_API_BASE=<url> # Mac/Linux
|
||||
setx LM_STUDIO_API_BASE <url> # Windows, restart shell after setx
|
||||
|
||||
aider --model lm_studio/<your-model-name>
|
||||
```
|
||||
|
||||
|
||||
|
||||
See the [model warnings](warnings.html)
|
||||
section for information on warnings which will occur
|
||||
when working with models that aider is not familiar with.
|
||||
@@ -20,24 +20,49 @@ python -m pip install -U aider-chat
|
||||
export OLLAMA_API_BASE=http://127.0.0.1:11434 # Mac/Linux
|
||||
setx OLLAMA_API_BASE http://127.0.0.1:11434 # Windows, restart shell after setx
|
||||
|
||||
aider --model ollama/<model>
|
||||
aider --model ollama_chat/<model>
|
||||
```
|
||||
|
||||
In particular, `llama3:70b` works well with aider:
|
||||
{: .note }
|
||||
Using `ollama_chat/` is recommended over `ollama/`.
|
||||
|
||||
|
||||
```
|
||||
ollama pull llama3:70b
|
||||
ollama serve
|
||||
|
||||
# In another terminal window...
|
||||
export OLLAMA_API_BASE=http://127.0.0.1:11434 # Mac/Linux
|
||||
setx OLLAMA_API_BASE http://127.0.0.1:11434 # Windows, restart shell after setx
|
||||
|
||||
aider --model ollama/llama3:70b
|
||||
```
|
||||
|
||||
See the [model warnings](warnings.html)
|
||||
section for information on warnings which will occur
|
||||
when working with models that aider is not familiar with.
|
||||
|
||||
## API Key
|
||||
|
||||
If you are using an ollama that requires an API key you can set `OLLAMA_API_KEY`:
|
||||
|
||||
```
|
||||
export OLLAMA_API_KEY=<api-key> # Mac/Linux
|
||||
setx OLLAMA_API_KEY <api-key> # Windows, restart shell after setx
|
||||
```
|
||||
|
||||
## Setting the context window size
|
||||
|
||||
[Ollama uses a 2k context window by default](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-specify-the-context-window-size),
|
||||
which is very small for working with aider.
|
||||
|
||||
Aider sets Ollama's context window to 8k by default.
|
||||
If you would like
|
||||
a larger context window
|
||||
you can use a
|
||||
[`.aider.model.settings.yml` file](https://aider.chat/docs/config/adv-model-settings.html#model-settings)
|
||||
like this:
|
||||
|
||||
```
|
||||
- name: ollama/qwen2.5-coder:32b-instruct-fp16
|
||||
extra_params:
|
||||
num_ctx: 8192
|
||||
```
|
||||
|
||||
Unlike most other LLM servers, Ollama does not throw an error if you submit
|
||||
a request that exceeds the context window.
|
||||
Instead, it just silently truncates the request by discarding the "oldest" messages
|
||||
in the chat to make it fit within the context window.
|
||||
So if your context window is too small, you won't get an error.
|
||||
Aider will probably just fail to work well and experience
|
||||
a lot of
|
||||
[file editing problems](https://aider.chat/docs/troubleshooting/edit-errors.html).
|
||||
|
||||
24
aider/website/docs/llms/xai.md
Normal file
24
aider/website/docs/llms/xai.md
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
parent: Connecting to LLMs
|
||||
nav_order: 400
|
||||
---
|
||||
|
||||
# xAI
|
||||
|
||||
You'll need a [xAI API key](https://console.x.ai.).
|
||||
|
||||
To use xAI:
|
||||
|
||||
```
|
||||
python -m pip install -U aider-chat
|
||||
|
||||
export XAI_API_KEY=<key> # Mac/Linux
|
||||
setx XAI_API_KEY <key> # Windows, restart shell after setx
|
||||
|
||||
aider --model xai/grok-beta
|
||||
|
||||
# List models available from xAI
|
||||
aider --list-models xai/
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ features and commands are most used.
|
||||
It also helps uncover bugs that users are experiencing, so that they can be fixed
|
||||
in upcoming releases.
|
||||
|
||||
## Enabling & disabling analytics
|
||||
## Disabling analytics
|
||||
|
||||
You can opt out of analytics forever by running this command one time:
|
||||
|
||||
@@ -39,10 +39,27 @@ You can opt out of analytics forever by running this command one time:
|
||||
aider --analytics-disable
|
||||
```
|
||||
|
||||
To enable analytics for a single session, you can run aider with `--analytics`.
|
||||
This will *not* have any effect if you have permanently disabled analytics with the previous command.
|
||||
## Enabling analytics
|
||||
|
||||
The first time, you will need to agree to opt-in.
|
||||
The `--[no-]analytics` switch controls whether analytics are enabled for the
|
||||
current session:
|
||||
|
||||
- `--analytics` will turn on analytics for the current session.
|
||||
This will *not* have any effect if you have permanently disabled analytics
|
||||
with `--analytics-disable`.
|
||||
If this is the first time you have enabled analytics, aider
|
||||
will confirm you wish to opt-in to analytics.
|
||||
- `--no-analytics` will turn off analytics for the current session.
|
||||
- By default, if you don't provide `--analytics` or `--no-analytics`,
|
||||
aider will enable analytics for a random subset of users.
|
||||
This will never happen if you have permanently disabled analytics
|
||||
with `--analytics-disable`.
|
||||
Randomly selected users will be asked if they wish to opt-in to analytics.
|
||||
|
||||
|
||||
## Opting in
|
||||
|
||||
The first time analytics are enabled, you will need to agree to opt-in.
|
||||
|
||||
```
|
||||
aider --analytics
|
||||
@@ -53,13 +70,8 @@ For more info: https://aider.chat/docs/more/analytics.html
|
||||
Allow collection of anonymous analytics to help improve aider? (Y)es/(N)o [Yes]:
|
||||
```
|
||||
|
||||
If you've added `analytics: true` to your
|
||||
[yaml config file](/docs/config/aider_conf.html),
|
||||
you can disable analytics for a single session, you can run:
|
||||
If you say "no", analytics will be permanently disabled.
|
||||
|
||||
```
|
||||
aider --no-analytics
|
||||
```
|
||||
|
||||
## Details about data being collected
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@ cog.out(model_list)
|
||||
]]]-->
|
||||
- anthropic.claude-3-5-haiku-20241022-v1:0
|
||||
- anthropic.claude-3-5-sonnet-20241022-v2:0
|
||||
- anthropic/claude-3-5-sonnet-20241022
|
||||
- claude-3-5-haiku-20241022
|
||||
- claude-3-5-sonnet-20240620
|
||||
- claude-3-5-sonnet-20241022
|
||||
@@ -91,11 +90,17 @@ cog.out(model_list)
|
||||
- openrouter/anthropic/claude-3.5-sonnet
|
||||
- us.anthropic.claude-3-5-haiku-20241022-v1:0
|
||||
- us.anthropic.claude-3-5-sonnet-20241022-v2:0
|
||||
- vertex_ai/claude-3-5-haiku
|
||||
- vertex_ai/claude-3-5-haiku@20241022
|
||||
- vertex_ai/claude-3-5-sonnet
|
||||
- vertex_ai/claude-3-5-sonnet-v2
|
||||
- vertex_ai/claude-3-5-sonnet-v2@20241022
|
||||
- vertex_ai/claude-3-5-sonnet@20240620
|
||||
- vertex_ai/claude-3-haiku
|
||||
- vertex_ai/claude-3-haiku@20240307
|
||||
- vertex_ai/claude-3-opus
|
||||
- vertex_ai/claude-3-opus@20240229
|
||||
- vertex_ai/claude-3-sonnet
|
||||
- vertex_ai/claude-3-sonnet@20240229
|
||||
<!--[[[end]]]-->
|
||||
|
||||
|
||||
@@ -95,3 +95,6 @@ io = InputOutput(yes=True)
|
||||
coder = Coder.create(model=model, fnames=fnames, io=io)
|
||||
```
|
||||
|
||||
{: .note }
|
||||
The python scripting API is not officially supported or documented,
|
||||
and could change in future releases without providing backwards compatibility.
|
||||
|
||||
@@ -19,31 +19,7 @@ LLM edits that are "almost" correctly formatted.
|
||||
But sometimes the LLM just won't cooperate.
|
||||
In these cases, here are some things you might try.
|
||||
|
||||
## Use a capable model
|
||||
|
||||
If possible try using GPT-4o, Claude 3.5 Sonnet or Claude 3 Opus,
|
||||
as they are the strongest and most capable models.
|
||||
|
||||
Weaker models
|
||||
are more prone to
|
||||
disobeying the system prompt instructions.
|
||||
Most local models are just barely capable of working with aider,
|
||||
so editing errors are probably unavoidable.
|
||||
|
||||
Local models which have been quantized are even more likely to have problems
|
||||
because they are not capable enough to follow aider's system prompts.
|
||||
|
||||
## Try the whole format
|
||||
|
||||
Run aider with `--edit-format whole` if the model is using a different edit format.
|
||||
You can see which edit format it is using in the announce lines:
|
||||
|
||||
```
|
||||
Aider v0.50.2-dev
|
||||
Models: claude-3-5-sonnet-20240620 with ♾️ diff edit format
|
||||
```
|
||||
|
||||
## Reduce distractions
|
||||
## Don't add too many files
|
||||
|
||||
Many LLMs now have very large context windows,
|
||||
but filling them with irrelevant code or conversation
|
||||
@@ -55,6 +31,38 @@ Aider also sends the LLM a [map of your entire git repo](https://aider.chat/docs
|
||||
- Use `/clear` to remove the conversation history, again to help the LLM focus.
|
||||
- Use `/tokens` to see how many tokens you are using for each message.
|
||||
|
||||
## Use a more capable model
|
||||
|
||||
If possible try using GPT-4o, Claude 3.5 Sonnet or Claude 3 Opus,
|
||||
as they are the strongest and most capable models.
|
||||
|
||||
Weaker models
|
||||
are more prone to
|
||||
disobeying the system prompt instructions.
|
||||
Most local models are just barely capable of working with aider,
|
||||
so editing errors are probably unavoidable.
|
||||
|
||||
## Local models: context window and quantization
|
||||
|
||||
Be especially careful about the
|
||||
[Ollama context window](https://aider.chat/docs/llms/ollama.html#setting-the-context-window-size)
|
||||
when working with local models.
|
||||
It defaults to be very small and silently discards data if you exceed it.
|
||||
|
||||
Local models which have been quantized are more likely to have editing problems
|
||||
because they are not capable enough to follow aider's system prompts.
|
||||
|
||||
## Try the whole edit format
|
||||
|
||||
Run aider with `--edit-format whole` if were using a different edit format.
|
||||
You can see which edit format it is using in the announce lines:
|
||||
|
||||
```
|
||||
Aider v0.50.2-dev
|
||||
Models: claude-3-5-sonnet-20240620 with ♾️ diff edit format
|
||||
```
|
||||
|
||||
|
||||
## More help
|
||||
|
||||
{% include help.md %}
|
||||
|
||||
@@ -33,6 +33,13 @@ To reduce output tokens:
|
||||
For more info: https://aider.chat/docs/token-limits.html
|
||||
```
|
||||
|
||||
{: .note }
|
||||
Aider never *enforces* token limits, it only *reports* token limit errors
|
||||
from the API provider.
|
||||
You probably don't need to
|
||||
[configure aider with the proper token limits](https://aider.chat/docs/config/adv-model-settings.html#context-window-size-and-token-costs)
|
||||
for unusual models.
|
||||
|
||||
## Input tokens & context window size
|
||||
|
||||
The most common problem is trying to send too much data to a
|
||||
|
||||
@@ -3,7 +3,14 @@ parent: Usage
|
||||
nav_order: 50
|
||||
description: Control aider with in-chat commands like /add, /model, etc.
|
||||
---
|
||||
|
||||
# In-chat commands
|
||||
{: .no_toc }
|
||||
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## Slash commands
|
||||
|
||||
Aider supports commands from within the chat, which all start with `/`.
|
||||
|
||||
@@ -24,6 +31,7 @@ cog.out(get_help_md())
|
||||
| **/copy** | Copy the last assistant message to the clipboard |
|
||||
| **/diff** | Display the diff of changes since the last message |
|
||||
| **/drop** | Remove files from the chat session to free up context space |
|
||||
| **/editor** | Open an editor to write a prompt |
|
||||
| **/exit** | Exit the application |
|
||||
| **/git** | Run a git command (output excluded from chat) |
|
||||
| **/help** | Ask questions about aider |
|
||||
@@ -69,8 +77,10 @@ The interactive prompt is built with [prompt-toolkit](https://github.com/prompt-
|
||||
|
||||
### Emacs
|
||||
|
||||
- `Up Arrow` : Scroll back through previously sent messages.
|
||||
- `Down Arrow` : Scroll forward through previously sent messages.
|
||||
- `Up Arrow` : Move up one line in the current message.
|
||||
- `Down Arrow` : Move down one line in the current message.
|
||||
- `Ctrl-Up` : Scroll back through previously sent messages.
|
||||
- `Ctrl-Down` : Scroll forward through previously sent messages.
|
||||
- `Ctrl-A` : Move cursor to the start of the line.
|
||||
- `Ctrl-B` : Move cursor back one character.
|
||||
- `Ctrl-D` : Delete the character under the cursor.
|
||||
@@ -87,8 +97,10 @@ The interactive prompt is built with [prompt-toolkit](https://github.com/prompt-
|
||||
|
||||
To use vi/vim keybindings, run aider with the `--vim` switch.
|
||||
|
||||
- `Up Arrow` : Scroll back through previously sent messages.
|
||||
- `Down Arrow` : Scroll forward through previously sent messages.
|
||||
- `Up Arrow` : Move up one line in the current message.
|
||||
- `Down Arrow` : Move down one line in the current message.
|
||||
- `Ctrl-Up` : Scroll back through previously sent messages.
|
||||
- `Ctrl-Down` : Scroll forward through previously sent messages.
|
||||
- `Esc` : Switch to command mode.
|
||||
- `i` : Switch to insert mode.
|
||||
- `a` : Move cursor one character to the right and switch to insert mode.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
parent: Usage
|
||||
nav_order: 60
|
||||
description: Using the chat, ask and help chat modes.
|
||||
description: Using the code, architect, ask and help chat modes.
|
||||
---
|
||||
|
||||
# Chat modes
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
nav_exclude: true
|
||||
---
|
||||
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self';
|
||||
script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com;
|
||||
connect-src http: https:;
|
||||
style-src 'self' 'unsafe-inline';">
|
||||
|
||||
# Shared aider chat transcript
|
||||
|
||||
A user has shared the following transcript of a pair programming chat session
|
||||
@@ -37,11 +43,29 @@ print("goodbye")
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js"></script>
|
||||
<script>
|
||||
function isValidUrl(url) {
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
return urlObj.protocol === 'http:' || urlObj.protocol === 'https:';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Configure marked with secure defaults
|
||||
marked.setOptions({
|
||||
headerIds: false,
|
||||
mangle: false
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
var conv = urlParams.get('mdurl');
|
||||
if (!conv) {
|
||||
if (!conv || !isValidUrl(conv)) {
|
||||
document.querySelector('#shared-transcript').innerHTML =
|
||||
'<div style="color: red; padding: 1em;">Error: Invalid or missing URL provided</div>';
|
||||
return;
|
||||
}
|
||||
document.getElementById('mdurl').href = conv;
|
||||
@@ -63,11 +87,14 @@ window.onload = function() {
|
||||
return line;
|
||||
}).join('\n');
|
||||
var html = marked.parse(markdown);
|
||||
var sanitizedHtml = DOMPurify.sanitize(html);
|
||||
var divElement = document.querySelector('#shared-transcript');
|
||||
divElement.innerHTML = html;
|
||||
divElement.innerHTML = sanitizedHtml;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching markdown:', error);
|
||||
document.querySelector('#shared-transcript').innerHTML =
|
||||
'<div style="color: red; padding: 1em;">Error: Failed to load chat transcript</div>';
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -47,10 +47,44 @@ def find_latest_benchmark_dir():
|
||||
print("Error: No benchmark directories found under tmp.benchmarks.")
|
||||
sys.exit(1)
|
||||
|
||||
latest_dir = max(
|
||||
benchmark_dirs,
|
||||
key=lambda d: next((f.stat().st_mtime for f in d.rglob("*.md") if f.is_file()), 0),
|
||||
)
|
||||
# Get current time and 24 hours ago
|
||||
now = datetime.datetime.now()
|
||||
day_ago = now - datetime.timedelta(days=1)
|
||||
|
||||
# Filter directories by name pattern YYYY-MM-DD-HH-MM-SS--
|
||||
recent_dirs = []
|
||||
for d in benchmark_dirs:
|
||||
try:
|
||||
# Extract datetime from directory name
|
||||
date_str = d.name[:19] # Takes YYYY-MM-DD-HH-MM-SS
|
||||
dir_date = datetime.datetime.strptime(date_str, "%Y-%m-%d-%H-%M-%S")
|
||||
if dir_date >= day_ago:
|
||||
recent_dirs.append(d)
|
||||
except ValueError:
|
||||
# Skip directories that don't match the expected format
|
||||
continue
|
||||
|
||||
if not recent_dirs:
|
||||
print("Error: No benchmark directories found from the last 24 hours.")
|
||||
sys.exit(1)
|
||||
|
||||
# Find directory with most recently modified .md file
|
||||
latest_dir = None
|
||||
latest_time = 0
|
||||
|
||||
for d in recent_dirs:
|
||||
# Look for .md files in subdirectories
|
||||
for md_file in d.glob("*/.*.md"):
|
||||
if md_file.is_file():
|
||||
mtime = md_file.stat().st_mtime
|
||||
if mtime > latest_time:
|
||||
latest_time = mtime
|
||||
latest_dir = d
|
||||
|
||||
if not latest_dir:
|
||||
print("Error: No .md files found in recent benchmark directories.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Using the most recently updated benchmark directory: {latest_dir.name}")
|
||||
return latest_dir
|
||||
|
||||
@@ -155,6 +189,9 @@ def main(
|
||||
tries: int = typer.Option(2, "--tries", "-r", help="Number of tries for running tests"),
|
||||
threads: int = typer.Option(1, "--threads", "-t", help="Number of threads to run in parallel"),
|
||||
num_tests: int = typer.Option(-1, "--num-tests", "-n", help="Number of tests to run"),
|
||||
num_ctx: Optional[int] = typer.Option(
|
||||
None, "--num-ctx", help="Override model context window size"
|
||||
),
|
||||
exercises_dir: str = typer.Option(
|
||||
EXERCISES_DIR_DEFAULT, "--exercises-dir", help="Directory with exercise files"
|
||||
),
|
||||
@@ -247,6 +284,7 @@ def main(
|
||||
max_apply_update_errors,
|
||||
editor_model,
|
||||
editor_edit_format,
|
||||
num_ctx,
|
||||
)
|
||||
|
||||
all_results.append(results)
|
||||
@@ -526,6 +564,7 @@ def run_test_real(
|
||||
max_apply_update_errors,
|
||||
editor_model,
|
||||
editor_edit_format,
|
||||
num_ctx=None,
|
||||
):
|
||||
if not os.path.isdir(testdir):
|
||||
print("Not a dir:", testdir)
|
||||
@@ -588,6 +627,11 @@ def run_test_real(
|
||||
editor_model=editor_model,
|
||||
editor_edit_format=editor_edit_format,
|
||||
)
|
||||
|
||||
if num_ctx:
|
||||
if not main_model.extra_params:
|
||||
main_model.extra_params = {}
|
||||
main_model.extra_params["num_ctx"] = num_ctx
|
||||
edit_format = edit_format or main_model.edit_format
|
||||
|
||||
dump(main_model)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
docker run \
|
||||
-it --rm \
|
||||
--add-host=host.docker.internal:host-gateway \
|
||||
-v `pwd`:/aider \
|
||||
-v `pwd`/tmp.benchmarks/.:/benchmarks \
|
||||
-e OPENAI_API_KEY=$OPENAI_API_KEY \
|
||||
|
||||
@@ -1,121 +1,168 @@
|
||||
from dataclasses import dataclass
|
||||
from datetime import date
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import yaml
|
||||
from imgcat import imgcat
|
||||
from matplotlib import rc
|
||||
|
||||
from aider.dump import dump # noqa: 401
|
||||
|
||||
@dataclass
|
||||
class ModelData:
|
||||
name: str
|
||||
release_date: date
|
||||
pass_rate: float
|
||||
|
||||
@property
|
||||
def color(self) -> str:
|
||||
model = self.name.lower()
|
||||
if "gemini" in model and "pro" in model:
|
||||
return "magenta"
|
||||
if "qwen" in model:
|
||||
return "darkblue"
|
||||
if "mistral" in model:
|
||||
return "cyan"
|
||||
if "haiku" in model:
|
||||
return "pink"
|
||||
if "deepseek" in model:
|
||||
return "brown"
|
||||
if "sonnet" in model:
|
||||
return "orange"
|
||||
if "-4o" in model:
|
||||
return "purple"
|
||||
if "gpt-4" in model:
|
||||
return "red"
|
||||
if "gpt-3.5" in model:
|
||||
return "green"
|
||||
return "lightblue"
|
||||
|
||||
@property
|
||||
def legend_label(self) -> str:
|
||||
model = self.name.lower()
|
||||
if "gemini" in model and "pro" in model:
|
||||
return "Gemini 1.5 Pro"
|
||||
if "claude-3-sonnet" in model:
|
||||
return "Sonnet"
|
||||
if "o1-preview" in model:
|
||||
return "O1 Preview"
|
||||
if "gpt-3.5" in model:
|
||||
return "GPT-3.5 Turbo"
|
||||
if "gpt-4-" in model and "-4o" not in model:
|
||||
return "GPT-4"
|
||||
if "qwen" in model:
|
||||
return "Qwen"
|
||||
if "-4o" in model:
|
||||
return "GPT-4o"
|
||||
if "haiku" in model:
|
||||
return "Haiku"
|
||||
if "deepseek" in model:
|
||||
return "DeepSeek"
|
||||
if "mistral" in model:
|
||||
return "Mistral"
|
||||
return model
|
||||
|
||||
|
||||
def get_model_color(model):
|
||||
default = "lightblue"
|
||||
class BenchmarkPlotter:
|
||||
LABEL_FONT_SIZE = 16
|
||||
|
||||
if model == "gpt-4o-mini":
|
||||
return default
|
||||
def __init__(self):
|
||||
self.setup_plot_style()
|
||||
|
||||
if "-4o" in model:
|
||||
return "purple"
|
||||
def setup_plot_style(self):
|
||||
plt.rcParams["hatch.linewidth"] = 0.5
|
||||
plt.rcParams["hatch.color"] = "#444444"
|
||||
rc("font", **{"family": "sans-serif", "sans-serif": ["Helvetica"], "size": 10})
|
||||
plt.rcParams["text.color"] = "#444444"
|
||||
|
||||
if "gpt-4" in model:
|
||||
return "red"
|
||||
def load_data(self, yaml_file: str) -> List[ModelData]:
|
||||
with open(yaml_file, "r") as file:
|
||||
data = yaml.safe_load(file)
|
||||
|
||||
if "gpt-3.5" in model:
|
||||
return "green"
|
||||
models = []
|
||||
for entry in data:
|
||||
if "released" in entry and "pass_rate_2" in entry:
|
||||
model = ModelData(
|
||||
name=entry["model"].split("(")[0].strip(),
|
||||
release_date=entry["released"],
|
||||
pass_rate=entry["pass_rate_2"],
|
||||
)
|
||||
models.append(model)
|
||||
return models
|
||||
|
||||
return default
|
||||
def create_figure(self) -> Tuple[plt.Figure, plt.Axes]:
|
||||
fig, ax = plt.subplots(figsize=(12, 8))
|
||||
ax.grid(axis="y", zorder=0, lw=0.2)
|
||||
for spine in ax.spines.values():
|
||||
spine.set_edgecolor("#DDDDDD")
|
||||
spine.set_linewidth(0.5)
|
||||
return fig, ax
|
||||
|
||||
def plot_model_series(self, ax: plt.Axes, models: List[ModelData]):
|
||||
# Group models by color
|
||||
color_groups: Dict[str, List[ModelData]] = {}
|
||||
for model in models:
|
||||
if model.color not in color_groups:
|
||||
color_groups[model.color] = []
|
||||
color_groups[model.color].append(model)
|
||||
|
||||
def plot_over_time(yaml_file):
|
||||
with open(yaml_file, "r") as file:
|
||||
data = yaml.safe_load(file)
|
||||
# Plot each color group
|
||||
for color, group in color_groups.items():
|
||||
sorted_group = sorted(group, key=lambda x: x.release_date)
|
||||
dates = [m.release_date for m in sorted_group]
|
||||
rates = [m.pass_rate for m in sorted_group]
|
||||
|
||||
dates = []
|
||||
pass_rates = []
|
||||
models = []
|
||||
# Plot line
|
||||
ax.plot(dates, rates, c=color, alpha=0.5, linewidth=1)
|
||||
|
||||
print("Debug: Raw data from YAML file:")
|
||||
print(data)
|
||||
# Plot points
|
||||
ax.scatter(dates, rates, c=color, alpha=0.5, s=120)
|
||||
|
||||
for entry in data:
|
||||
if "released" in entry and "pass_rate_2" in entry:
|
||||
dates.append(entry["released"])
|
||||
pass_rates.append(entry["pass_rate_2"])
|
||||
models.append(entry["model"].split("(")[0].strip())
|
||||
# Add label for first point
|
||||
first_model = sorted_group[0]
|
||||
ax.annotate(
|
||||
first_model.legend_label,
|
||||
(first_model.release_date, first_model.pass_rate),
|
||||
xytext=(10, 5),
|
||||
textcoords="offset points",
|
||||
color=color,
|
||||
alpha=0.8,
|
||||
fontsize=self.LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
print("Debug: Processed data:")
|
||||
print("Dates:", dates)
|
||||
print("Pass rates:", pass_rates)
|
||||
print("Models:", models)
|
||||
|
||||
if not dates or not pass_rates:
|
||||
print(
|
||||
"Error: No data to plot. Check if the YAML file is empty or if the data is in the"
|
||||
" expected format."
|
||||
def set_labels_and_style(self, ax: plt.Axes):
|
||||
ax.set_xlabel("Model release date", fontsize=18, color="#555")
|
||||
ax.set_ylabel(
|
||||
"Aider code editing benchmark,\npercent completed correctly", fontsize=18, color="#555"
|
||||
)
|
||||
return
|
||||
ax.set_title("LLM code editing skill by model release date", fontsize=20)
|
||||
ax.set_ylim(30, 90)
|
||||
plt.xticks(fontsize=14, rotation=45, ha="right")
|
||||
plt.tight_layout(pad=1.0)
|
||||
|
||||
plt.rcParams["hatch.linewidth"] = 0.5
|
||||
plt.rcParams["hatch.color"] = "#444444"
|
||||
def save_and_display(self, fig: plt.Figure):
|
||||
plt.savefig("aider/website/assets/models-over-time.png")
|
||||
plt.savefig("aider/website/assets/models-over-time.svg")
|
||||
imgcat(fig)
|
||||
|
||||
rc("font", **{"family": "sans-serif", "sans-serif": ["Helvetica"], "size": 10})
|
||||
plt.rcParams["text.color"] = "#444444"
|
||||
|
||||
fig, ax = plt.subplots(figsize=(12, 6)) # Increase figure size for better visibility
|
||||
|
||||
print("Debug: Figure created. Plotting data...")
|
||||
ax.grid(axis="y", zorder=0, lw=0.2)
|
||||
for spine in ax.spines.values():
|
||||
spine.set_edgecolor("#DDDDDD")
|
||||
spine.set_linewidth(0.5)
|
||||
|
||||
colors = [get_model_color(model) for model in models]
|
||||
|
||||
# Separate data points by color
|
||||
purple_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "purple"]
|
||||
red_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "red"]
|
||||
green_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "green"]
|
||||
|
||||
# Plot lines for purple, red, and green points
|
||||
if purple_points:
|
||||
purple_dates, purple_rates = zip(*sorted(purple_points))
|
||||
ax.plot(purple_dates, purple_rates, c="purple", alpha=0.5, linewidth=1)
|
||||
if red_points:
|
||||
red_dates, red_rates = zip(*sorted(red_points))
|
||||
ax.plot(red_dates, red_rates, c="red", alpha=0.5, linewidth=1)
|
||||
if green_points:
|
||||
green_dates, green_rates = zip(*sorted(green_points))
|
||||
ax.plot(green_dates, green_rates, c="green", alpha=0.5, linewidth=1)
|
||||
|
||||
# Plot all points
|
||||
ax.scatter(dates, pass_rates, c=colors, alpha=0.5, s=120)
|
||||
|
||||
for i, model in enumerate(models):
|
||||
ax.annotate(
|
||||
model,
|
||||
(dates[i], pass_rates[i]),
|
||||
fontsize=8,
|
||||
alpha=0.75,
|
||||
xytext=(5, 5),
|
||||
textcoords="offset points",
|
||||
)
|
||||
|
||||
ax.set_xlabel("Model release date", fontsize=18, color="#555")
|
||||
ax.set_ylabel(
|
||||
"Aider code editing benchmark,\npercent completed correctly", fontsize=18, color="#555"
|
||||
)
|
||||
ax.set_title("LLM code editing skill by model release date", fontsize=20)
|
||||
ax.set_ylim(0, 100) # Adjust y-axis limit to accommodate higher values
|
||||
plt.xticks(fontsize=14, rotation=45, ha="right") # Rotate x-axis labels for better readability
|
||||
plt.tight_layout(pad=3.0)
|
||||
|
||||
print("Debug: Saving figures...")
|
||||
plt.savefig("tmp_over_time.png")
|
||||
plt.savefig("tmp_over_time.svg")
|
||||
|
||||
print("Debug: Displaying figure with imgcat...")
|
||||
imgcat(fig)
|
||||
|
||||
print("Debug: Figure generation complete.")
|
||||
def plot(self, yaml_file: str):
|
||||
models = self.load_data(yaml_file)
|
||||
fig, ax = self.create_figure()
|
||||
self.plot_model_series(ax, models)
|
||||
self.set_labels_and_style(ax)
|
||||
self.save_and_display(fig)
|
||||
|
||||
|
||||
# Example usage
|
||||
plot_over_time("aider/website/_data/edit_leaderboard.yml")
|
||||
def main():
|
||||
plotter = BenchmarkPlotter()
|
||||
models = plotter.load_data("aider/website/_data/edit_leaderboard.yml")
|
||||
|
||||
# Print release dates and model names
|
||||
for model in sorted(models, key=lambda x: x.release_date):
|
||||
print(f"{model.release_date}: {model.name}")
|
||||
|
||||
plotter.plot("aider/website/_data/edit_leaderboard.yml")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -58,6 +58,7 @@ include = ["aider*", "aider.website"]
|
||||
"docs/unified-diffs.md",
|
||||
"docs/leaderboards/index.md",
|
||||
"assets/**",
|
||||
"**/.DS_Store",
|
||||
# [[[end]]]
|
||||
]
|
||||
|
||||
@@ -66,7 +67,7 @@ requires = ["setuptools>=68", "setuptools_scm[toml]>=8"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools_scm]
|
||||
write_to = "aider/__version__.py"
|
||||
write_to = "aider/_version.py"
|
||||
|
||||
[tool.codespell]
|
||||
skip = "*.svg,Gemfile.lock"
|
||||
|
||||
@@ -6,5 +6,7 @@ testpaths =
|
||||
tests/help
|
||||
tests/browser
|
||||
tests/scrape
|
||||
|
||||
|
||||
env =
|
||||
AIDER_ANALYTICS=false
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
aiohappyeyeballs==2.4.3
|
||||
# via aiohttp
|
||||
aiohttp==3.10.10
|
||||
aiohttp==3.11.7
|
||||
# via litellm
|
||||
aiosignal==1.3.1
|
||||
# via aiohttp
|
||||
@@ -62,11 +62,11 @@ gitdb==4.0.11
|
||||
# via gitpython
|
||||
gitpython==3.1.43
|
||||
# via -r requirements/requirements.in
|
||||
grep-ast==0.3.3
|
||||
grep-ast==0.4.1
|
||||
# via -r requirements/requirements.in
|
||||
h11==0.14.0
|
||||
# via httpcore
|
||||
httpcore==1.0.6
|
||||
httpcore==1.0.7
|
||||
# via httpx
|
||||
httpx==0.27.2
|
||||
# via openai
|
||||
@@ -86,9 +86,9 @@ importlib-resources==6.4.5
|
||||
# via -r requirements/requirements.in
|
||||
jinja2==3.1.4
|
||||
# via litellm
|
||||
jiter==0.7.0
|
||||
jiter==0.8.0
|
||||
# via openai
|
||||
json5==0.9.25
|
||||
json5==0.10.0
|
||||
# via -r requirements/requirements.in
|
||||
jsonschema==4.23.0
|
||||
# via
|
||||
@@ -96,7 +96,7 @@ jsonschema==4.23.0
|
||||
# litellm
|
||||
jsonschema-specifications==2024.10.1
|
||||
# via jsonschema
|
||||
litellm==1.51.2
|
||||
litellm==1.52.16
|
||||
# via -r requirements/requirements.in
|
||||
markdown-it-py==3.0.0
|
||||
# via rich
|
||||
@@ -120,9 +120,9 @@ numpy==1.26.4
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
# scipy
|
||||
openai==1.53.0
|
||||
openai==1.55.2
|
||||
# via litellm
|
||||
packaging==24.1
|
||||
packaging==24.2
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
# huggingface-hub
|
||||
@@ -134,12 +134,14 @@ pexpect==4.9.0
|
||||
# via -r requirements/requirements.in
|
||||
pillow==10.4.0
|
||||
# via -r requirements/requirements.in
|
||||
posthog==3.7.0
|
||||
posthog==3.7.3
|
||||
# via -r requirements/requirements.in
|
||||
prompt-toolkit==3.0.48
|
||||
# via -r requirements/requirements.in
|
||||
propcache==0.2.0
|
||||
# via yarl
|
||||
# via
|
||||
# aiohttp
|
||||
# yarl
|
||||
psutil==6.1.0
|
||||
# via -r requirements/requirements.in
|
||||
ptyprocess==0.7.0
|
||||
@@ -148,11 +150,11 @@ pycodestyle==2.12.1
|
||||
# via flake8
|
||||
pycparser==2.22
|
||||
# via cffi
|
||||
pydantic==2.9.2
|
||||
pydantic==2.10.2
|
||||
# via
|
||||
# litellm
|
||||
# openai
|
||||
pydantic-core==2.23.4
|
||||
pydantic-core==2.27.1
|
||||
# via pydantic
|
||||
pydub==0.25.1
|
||||
# via -r requirements/requirements.in
|
||||
@@ -176,7 +178,7 @@ referencing==0.35.1
|
||||
# via
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
regex==2024.9.11
|
||||
regex==2024.11.6
|
||||
# via tiktoken
|
||||
requests==2.32.3
|
||||
# via
|
||||
@@ -185,9 +187,9 @@ requests==2.32.3
|
||||
# mixpanel
|
||||
# posthog
|
||||
# tiktoken
|
||||
rich==13.9.3
|
||||
rich==13.9.4
|
||||
# via -r requirements/requirements.in
|
||||
rpds-py==0.20.1
|
||||
rpds-py==0.21.0
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
@@ -217,7 +219,7 @@ tokenizers==0.19.1
|
||||
# via
|
||||
# -r requirements/requirements.in
|
||||
# litellm
|
||||
tqdm==4.66.6
|
||||
tqdm==4.67.1
|
||||
# via
|
||||
# huggingface-hub
|
||||
# openai
|
||||
@@ -239,7 +241,7 @@ urllib3==2.2.3
|
||||
# requests
|
||||
wcwidth==0.2.13
|
||||
# via prompt-toolkit
|
||||
yarl==1.17.1
|
||||
yarl==1.18.0
|
||||
# via aiohttp
|
||||
zipp==3.20.2
|
||||
zipp==3.21.0
|
||||
# via importlib-metadata
|
||||
|
||||
@@ -4,109 +4,109 @@
|
||||
#
|
||||
# pip-compile --constraint=requirements.txt --constraint=requirements/requirements-dev.txt --constraint=requirements/requirements-help.txt --output-file=requirements/requirements-browser.txt requirements/requirements-browser.in
|
||||
#
|
||||
altair==5.4.1
|
||||
altair==5.5.0
|
||||
# via streamlit
|
||||
attrs==24.2.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# jsonschema
|
||||
# referencing
|
||||
blinker==1.8.2
|
||||
blinker==1.9.0
|
||||
# via streamlit
|
||||
cachetools==5.5.0
|
||||
# via streamlit
|
||||
certifi==2024.8.30
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# requests
|
||||
charset-normalizer==3.4.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# requests
|
||||
click==8.1.7
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# streamlit
|
||||
gitdb==4.0.11
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# gitpython
|
||||
gitpython==3.1.43
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# streamlit
|
||||
idna==3.10
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# requests
|
||||
jinja2==3.1.4
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# altair
|
||||
# pydeck
|
||||
jsonschema==4.23.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# altair
|
||||
jsonschema-specifications==2024.10.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# jsonschema
|
||||
markdown-it-py==3.0.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# rich
|
||||
markupsafe==3.0.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# jinja2
|
||||
mdurl==0.1.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# markdown-it-py
|
||||
narwhals==1.12.1
|
||||
narwhals==1.14.2
|
||||
# via altair
|
||||
numpy==1.26.4
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# pandas
|
||||
# pydeck
|
||||
# streamlit
|
||||
packaging==24.1
|
||||
packaging==24.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# altair
|
||||
@@ -117,27 +117,27 @@ pandas==2.2.3
|
||||
# streamlit
|
||||
pillow==10.4.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# streamlit
|
||||
protobuf==5.28.3
|
||||
# via streamlit
|
||||
pyarrow==18.0.0
|
||||
pyarrow==18.1.0
|
||||
# via streamlit
|
||||
pydeck==0.9.1
|
||||
# via streamlit
|
||||
pygments==2.18.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# rich
|
||||
python-dateutil==2.9.0.post0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# pandas
|
||||
pytz==2024.2
|
||||
@@ -146,41 +146,41 @@ pytz==2024.2
|
||||
# pandas
|
||||
referencing==0.35.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
requests==2.32.3
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# streamlit
|
||||
rich==13.9.3
|
||||
rich==13.9.4
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# streamlit
|
||||
rpds-py==0.20.1
|
||||
rpds-py==0.21.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# jsonschema
|
||||
# referencing
|
||||
six==1.16.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# python-dateutil
|
||||
smmap==5.0.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# gitdb
|
||||
streamlit==1.39.0
|
||||
streamlit==1.40.2
|
||||
# via -r requirements/requirements-browser.in
|
||||
tenacity==8.5.0
|
||||
# via
|
||||
@@ -188,12 +188,12 @@ tenacity==8.5.0
|
||||
# streamlit
|
||||
toml==0.10.2
|
||||
# via streamlit
|
||||
tornado==6.4.1
|
||||
tornado==6.4.2
|
||||
# via streamlit
|
||||
typing-extensions==4.12.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# altair
|
||||
@@ -204,8 +204,8 @@ tzdata==2024.2
|
||||
# pandas
|
||||
urllib3==2.2.3
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
# requests
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# pip-compile --output-file=requirements-dev.txt requirements-dev.in --upgrade
|
||||
#
|
||||
pytest
|
||||
pytest-env
|
||||
pip-tools
|
||||
lox
|
||||
matplotlib
|
||||
|
||||
@@ -12,27 +12,27 @@ build==1.2.2.post1
|
||||
# via pip-tools
|
||||
certifi==2024.8.30
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
cfgv==3.4.0
|
||||
# via pre-commit
|
||||
charset-normalizer==3.4.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
click==8.1.7
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# pip-tools
|
||||
# typer
|
||||
codespell==2.3.0
|
||||
# via -r requirements/requirements-dev.in
|
||||
cogapp==3.4.1
|
||||
# via -r requirements/requirements-dev.in
|
||||
contourpy==1.3.0
|
||||
contourpy==1.3.1
|
||||
# via matplotlib
|
||||
cycler==0.12.1
|
||||
# via matplotlib
|
||||
@@ -48,28 +48,28 @@ docutils==0.21.2
|
||||
# sphinx-rtd-theme
|
||||
filelock==3.16.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# virtualenv
|
||||
fonttools==4.54.1
|
||||
fonttools==4.55.0
|
||||
# via matplotlib
|
||||
identify==2.6.1
|
||||
identify==2.6.3
|
||||
# via pre-commit
|
||||
idna==3.10
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
imagesize==1.4.1
|
||||
# via sphinx
|
||||
imgcat==0.5.0
|
||||
imgcat==0.6.0
|
||||
# via -r requirements/requirements-dev.in
|
||||
iniconfig==2.0.0
|
||||
# via pytest
|
||||
jinja2==3.1.4
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# sphinx
|
||||
kiwisolver==1.4.7
|
||||
# via matplotlib
|
||||
@@ -77,20 +77,20 @@ lox==0.12.0
|
||||
# via -r requirements/requirements-dev.in
|
||||
markdown-it-py==3.0.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# rich
|
||||
markupsafe==3.0.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# jinja2
|
||||
matplotlib==3.9.2
|
||||
# via -r requirements/requirements-dev.in
|
||||
mdurl==0.1.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# markdown-it-py
|
||||
multiprocess==0.70.17
|
||||
# via pathos
|
||||
@@ -98,15 +98,15 @@ nodeenv==1.9.1
|
||||
# via pre-commit
|
||||
numpy==1.26.4
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# contourpy
|
||||
# matplotlib
|
||||
# pandas
|
||||
packaging==24.1
|
||||
packaging==24.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# build
|
||||
# matplotlib
|
||||
# pytest
|
||||
@@ -117,8 +117,8 @@ pathos==0.3.3
|
||||
# via lox
|
||||
pillow==10.4.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# matplotlib
|
||||
pip-tools==7.4.1
|
||||
# via -r requirements/requirements-dev.in
|
||||
@@ -134,8 +134,8 @@ pre-commit==4.0.1
|
||||
# via -r requirements/requirements-dev.in
|
||||
pygments==2.18.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# rich
|
||||
# sphinx
|
||||
pyparsing==3.2.0
|
||||
@@ -145,29 +145,33 @@ pyproject-hooks==1.2.0
|
||||
# build
|
||||
# pip-tools
|
||||
pytest==8.3.3
|
||||
# via
|
||||
# -r requirements/requirements-dev.in
|
||||
# pytest-env
|
||||
pytest-env==1.1.5
|
||||
# via -r requirements/requirements-dev.in
|
||||
python-dateutil==2.9.0.post0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# matplotlib
|
||||
# pandas
|
||||
pytz==2024.2
|
||||
# via pandas
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# pre-commit
|
||||
requests==2.32.3
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# sphinx
|
||||
rich==13.9.3
|
||||
rich==13.9.4
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# typer
|
||||
semver==3.0.2
|
||||
# via -r requirements/requirements-dev.in
|
||||
@@ -175,8 +179,8 @@ shellingham==1.5.4
|
||||
# via typer
|
||||
six==1.16.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# python-dateutil
|
||||
snowballstemmer==2.2.0
|
||||
# via sphinx
|
||||
@@ -184,7 +188,7 @@ sphinx==8.1.3
|
||||
# via
|
||||
# sphinx-rtd-theme
|
||||
# sphinxcontrib-jquery
|
||||
sphinx-rtd-theme==3.0.1
|
||||
sphinx-rtd-theme==3.0.2
|
||||
# via lox
|
||||
sphinxcontrib-applehelp==2.0.0
|
||||
# via sphinx
|
||||
@@ -200,23 +204,23 @@ sphinxcontrib-qthelp==2.0.0
|
||||
# via sphinx
|
||||
sphinxcontrib-serializinghtml==2.0.0
|
||||
# via sphinx
|
||||
typer==0.12.5
|
||||
typer==0.13.1
|
||||
# via -r requirements/requirements-dev.in
|
||||
typing-extensions==4.12.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# typer
|
||||
tzdata==2024.2
|
||||
# via pandas
|
||||
urllib3==2.2.3
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# requests
|
||||
virtualenv==20.27.1
|
||||
virtualenv==20.28.0
|
||||
# via pre-commit
|
||||
wheel==0.44.0
|
||||
wheel==0.45.1
|
||||
# via pip-tools
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
|
||||
@@ -6,79 +6,81 @@
|
||||
#
|
||||
aiohappyeyeballs==2.4.3
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
aiohttp==3.10.10
|
||||
aiohttp==3.11.7
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# huggingface-hub
|
||||
# llama-index-core
|
||||
aiosignal==1.3.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
annotated-types==0.7.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# pydantic
|
||||
anyio==4.6.2.post1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# httpx
|
||||
attrs==24.2.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
certifi==2024.8.30
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# httpcore
|
||||
# httpx
|
||||
# requests
|
||||
charset-normalizer==3.4.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# requests
|
||||
click==8.1.7
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# nltk
|
||||
dataclasses-json==0.6.7
|
||||
# via llama-index-core
|
||||
deprecated==1.2.14
|
||||
deprecated==1.2.15
|
||||
# via llama-index-core
|
||||
dirtyjson==1.0.8
|
||||
# via llama-index-core
|
||||
filelock==3.16.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# huggingface-hub
|
||||
# torch
|
||||
# transformers
|
||||
filetype==1.2.0
|
||||
# via llama-index-core
|
||||
frozenlist==1.5.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
# aiosignal
|
||||
fsspec==2024.10.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# huggingface-hub
|
||||
# llama-index-core
|
||||
# torch
|
||||
@@ -88,31 +90,31 @@ greenlet==3.0.3
|
||||
# sqlalchemy
|
||||
h11==0.14.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# httpcore
|
||||
httpcore==1.0.6
|
||||
httpcore==1.0.7
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# httpx
|
||||
httpx==0.27.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# llama-index-core
|
||||
huggingface-hub[inference]==0.26.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# llama-index-embeddings-huggingface
|
||||
# sentence-transformers
|
||||
# tokenizers
|
||||
# transformers
|
||||
idna==3.10
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# anyio
|
||||
# httpx
|
||||
@@ -120,34 +122,34 @@ idna==3.10
|
||||
# yarl
|
||||
jinja2==3.1.4
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# torch
|
||||
joblib==1.4.2
|
||||
# via
|
||||
# nltk
|
||||
# scikit-learn
|
||||
llama-index-core==0.11.21
|
||||
llama-index-core==0.12.0
|
||||
# via
|
||||
# -r requirements/requirements-help.in
|
||||
# llama-index-embeddings-huggingface
|
||||
llama-index-embeddings-huggingface==0.3.1
|
||||
llama-index-embeddings-huggingface==0.4.0
|
||||
# via -r requirements/requirements-help.in
|
||||
markupsafe==3.0.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# jinja2
|
||||
marshmallow==3.23.0
|
||||
marshmallow==3.23.1
|
||||
# via dataclasses-json
|
||||
mpmath==1.3.0
|
||||
# via sympy
|
||||
multidict==6.1.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
# yarl
|
||||
mypy-extensions==1.0.0
|
||||
@@ -156,70 +158,71 @@ nest-asyncio==1.6.0
|
||||
# via llama-index-core
|
||||
networkx==3.2.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# llama-index-core
|
||||
# torch
|
||||
nltk==3.9.1
|
||||
# via llama-index-core
|
||||
numpy==1.26.4
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# llama-index-core
|
||||
# scikit-learn
|
||||
# scipy
|
||||
# transformers
|
||||
packaging==24.1
|
||||
packaging==24.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# huggingface-hub
|
||||
# marshmallow
|
||||
# transformers
|
||||
pillow==10.4.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# llama-index-core
|
||||
# sentence-transformers
|
||||
propcache==0.2.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
# yarl
|
||||
pydantic==2.9.2
|
||||
pydantic==2.10.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# llama-index-core
|
||||
pydantic-core==2.23.4
|
||||
pydantic-core==2.27.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# pydantic
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# huggingface-hub
|
||||
# llama-index-core
|
||||
# transformers
|
||||
regex==2024.9.11
|
||||
regex==2024.11.6
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# nltk
|
||||
# tiktoken
|
||||
# transformers
|
||||
requests==2.32.3
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# huggingface-hub
|
||||
# llama-index-core
|
||||
@@ -231,16 +234,16 @@ scikit-learn==1.5.2
|
||||
# via sentence-transformers
|
||||
scipy==1.13.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# scikit-learn
|
||||
# sentence-transformers
|
||||
sentence-transformers==3.2.1
|
||||
sentence-transformers==3.3.1
|
||||
# via llama-index-embeddings-huggingface
|
||||
sniffio==1.3.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# anyio
|
||||
# httpx
|
||||
sqlalchemy[asyncio]==2.0.36
|
||||
@@ -255,20 +258,20 @@ threadpoolctl==3.5.0
|
||||
# via scikit-learn
|
||||
tiktoken==0.8.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# llama-index-core
|
||||
tokenizers==0.19.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# transformers
|
||||
torch==2.2.2
|
||||
# via sentence-transformers
|
||||
tqdm==4.66.6
|
||||
tqdm==4.67.1
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# huggingface-hub
|
||||
# llama-index-core
|
||||
# nltk
|
||||
@@ -278,8 +281,8 @@ transformers==4.44.2
|
||||
# via sentence-transformers
|
||||
typing-extensions==4.12.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# huggingface-hub
|
||||
# llama-index-core
|
||||
@@ -294,16 +297,16 @@ typing-inspect==0.9.0
|
||||
# llama-index-core
|
||||
urllib3==2.2.3
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# requests
|
||||
wrapt==1.16.0
|
||||
wrapt==1.17.0
|
||||
# via
|
||||
# deprecated
|
||||
# llama-index-core
|
||||
yarl==1.17.1
|
||||
yarl==1.18.0
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# aiohttp
|
||||
|
||||
@@ -15,8 +15,8 @@ pyee==12.0.0
|
||||
# via playwright
|
||||
typing-extensions==4.12.2
|
||||
# via
|
||||
# -c /Users/gauthier/Projects/aider/requirements.txt
|
||||
# -c requirements.txt
|
||||
# -c requirements/../requirements.txt
|
||||
# -c requirements/requirements-browser.txt
|
||||
# -c requirements/requirements-dev.txt
|
||||
# -c requirements/requirements-help.txt
|
||||
|
||||
@@ -15,6 +15,6 @@ RUN bundle install --retry 5 --jobs 20
|
||||
ENTRYPOINT [ "docker-entrypoint.sh" ]
|
||||
|
||||
# bundle exec jekyll serve --force_polling -H 0.0.0.0 -P 4000
|
||||
CMD [ "bundle", "exec", "jekyll", "serve", "--force_polling", "-H", "0.0.0.0", "-P", "4000" ]
|
||||
CMD [ "bundle", "exec", "jekyll", "serve", "--verbose", "--trace", "--force_polling", "-H", "0.0.0.0", "-P", "4000" ]
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
@@ -23,8 +24,10 @@ def blame(start_tag, end_tag=None):
|
||||
files = [
|
||||
f
|
||||
for f in files
|
||||
if f.endswith((".py", ".scm", ".sh", "Dockerfile", "Gemfile"))
|
||||
if f.endswith((".js", ".py", ".scm", ".sh", "Dockerfile", "Gemfile"))
|
||||
or (f.startswith(".github/workflows/") and f.endswith(".yml"))
|
||||
or f == "aider/website/share/index.md"
|
||||
or f == "aider/website/docs/leaderboards/index.md"
|
||||
]
|
||||
files = [f for f in files if not f.endswith("prompts.py")]
|
||||
|
||||
@@ -141,8 +144,31 @@ def main():
|
||||
return
|
||||
|
||||
if args.all_since:
|
||||
results = process_all_tags_since(args.start_tag)
|
||||
yaml_output = yaml.dump(results, sort_keys=True)
|
||||
new_results = process_all_tags_since(args.start_tag)
|
||||
|
||||
# If output file exists, read and update it
|
||||
existing_results = []
|
||||
if args.output and os.path.exists(args.output):
|
||||
with open(args.output, "r") as f:
|
||||
existing_results = yaml.safe_load(f) or []
|
||||
|
||||
# Create a map of start_tag->end_tag to result for existing entries
|
||||
existing_map = {(r["start_tag"], r["end_tag"]): i for i, r in enumerate(existing_results)}
|
||||
|
||||
# Update or append new results
|
||||
for new_result in new_results:
|
||||
key = (new_result["start_tag"], new_result["end_tag"])
|
||||
if key in existing_map:
|
||||
# Replace existing entry
|
||||
existing_results[existing_map[key]] = new_result
|
||||
else:
|
||||
# Append new entry
|
||||
existing_results.append(new_result)
|
||||
|
||||
# Sort results by start_tag
|
||||
existing_results.sort(key=lambda x: semver.Version.parse(x["start_tag"][1:]))
|
||||
|
||||
yaml_output = yaml.dump(existing_results, sort_keys=True)
|
||||
else:
|
||||
all_file_counts, grand_total, total_lines, aider_total, aider_percentage, end_date = blame(
|
||||
args.start_tag, args.end_tag
|
||||
|
||||
@@ -22,15 +22,29 @@ def has_been_reopened(issue_number):
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
DUPLICATE_COMMENT = """Thanks for trying aider and filing this issue.
|
||||
BOT_SUFFIX = """
|
||||
|
||||
Note: [A bot script](https://github.com/Aider-AI/aider/blob/main/scripts/issues.py) made these updates to the issue.
|
||||
""" # noqa
|
||||
|
||||
DUPLICATE_COMMENT = (
|
||||
"""Thanks for trying aider and filing this issue.
|
||||
|
||||
This looks like a duplicate of #{oldest_issue_number}. Please see the comments there for more information, and feel free to continue the discussion within that issue.
|
||||
|
||||
I'm going to close this issue for now. But please let me know if you think this is actually a distinct issue and I will reopen this issue.""" # noqa
|
||||
+ BOT_SUFFIX
|
||||
)
|
||||
|
||||
STALE_COMMENT = """I'm labeling this issue as stale because it has been open for 2 weeks with no activity. If there are no additional comments, it will be closed in 7 days.""" # noqa
|
||||
STALE_COMMENT = (
|
||||
"""I'm labeling this issue as stale because it has been open for 2 weeks with no activity. If there are no additional comments, I will close it in 7 days.""" # noqa
|
||||
+ BOT_SUFFIX
|
||||
)
|
||||
|
||||
CLOSE_STALE_COMMENT = """I'm closing this issue because it has been stalled for 3 weeks with no activity. Feel free to add a comment here and we can re-open it. Or feel free to file a new issue at any time.""" # noqa
|
||||
CLOSE_STALE_COMMENT = (
|
||||
"""I'm closing this issue because it has been stalled for 3 weeks with no activity. Feel free to add a comment here and we can re-open it. Or feel free to file a new issue at any time.""" # noqa
|
||||
+ BOT_SUFFIX
|
||||
)
|
||||
|
||||
# GitHub API configuration
|
||||
GITHUB_API_URL = "https://api.github.com"
|
||||
@@ -279,7 +293,7 @@ def handle_stale_closing(all_issues, auto_yes):
|
||||
continue
|
||||
|
||||
# Add closing comment
|
||||
comment_url = f"{GITHUB_API_URL}/repos/{REPO_OWNER}/{REPO_NAME}/issues/{issue['number']}/comments"
|
||||
comment_url = f"{GITHUB_API_URL}/repos/{REPO_OWNER}/{REPO_NAME}/issues/{issue['number']}/comments" # noqa
|
||||
response = requests.post(
|
||||
comment_url, headers=headers, json={"body": CLOSE_STALE_COMMENT}
|
||||
)
|
||||
|
||||
@@ -24,6 +24,7 @@ cog $ARG \
|
||||
aider/website/docs/config/options.md \
|
||||
aider/website/docs/config/aider_conf.md \
|
||||
aider/website/docs/config/adv-model-settings.md \
|
||||
aider/website/docs/config/model-aliases.md \
|
||||
aider/website/docs/leaderboards/index.md \
|
||||
aider/website/docs/llms/other.md \
|
||||
aider/website/docs/more/infinite-output.md \
|
||||
|
||||
125
scripts/update-history.py
Executable file
125
scripts/update-history.py
Executable file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from aider import __version__
|
||||
|
||||
|
||||
def get_base_version():
|
||||
# Parse current version like "0.64.2.dev" to get major.minor
|
||||
match = re.match(r"(\d+\.\d+)", __version__)
|
||||
if not match:
|
||||
raise ValueError(f"Could not parse version: {__version__}")
|
||||
return match.group(1) + ".0"
|
||||
|
||||
|
||||
def run_git_log():
|
||||
base_ver = get_base_version()
|
||||
cmd = [
|
||||
"git",
|
||||
"log",
|
||||
"-p",
|
||||
f"v{base_ver}..HEAD",
|
||||
"--",
|
||||
"aider/",
|
||||
":!aider/website/",
|
||||
":!scripts/",
|
||||
":!HISTORY.md",
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
return result.stdout
|
||||
|
||||
|
||||
def main():
|
||||
# Get the git log output
|
||||
diff_content = run_git_log()
|
||||
|
||||
# Extract relevant portion of HISTORY.md
|
||||
base_ver = get_base_version()
|
||||
with open("HISTORY.md", "r") as f:
|
||||
history_content = f.read()
|
||||
|
||||
# Find the section for this version
|
||||
version_header = f"### Aider v{base_ver}"
|
||||
start_idx = history_content.find("# Release history")
|
||||
if start_idx == -1:
|
||||
raise ValueError("Could not find start of release history")
|
||||
|
||||
# Find where this version's section ends
|
||||
version_idx = history_content.find(version_header, start_idx)
|
||||
if version_idx == -1:
|
||||
raise ValueError(f"Could not find version header: {version_header}")
|
||||
|
||||
# Find the next version header after this one
|
||||
next_version_idx = history_content.find("\n### Aider v", version_idx + len(version_header))
|
||||
if next_version_idx == -1:
|
||||
# No next version found, use the rest of the file
|
||||
relevant_history = history_content[start_idx:]
|
||||
else:
|
||||
# Extract just up to the next version
|
||||
relevant_history = history_content[start_idx:next_version_idx]
|
||||
|
||||
# Save relevant portions to temporary files
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".diff") as tmp_diff:
|
||||
tmp_diff.write(diff_content)
|
||||
diff_path = tmp_diff.name
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".md") as tmp_hist:
|
||||
tmp_hist.write(relevant_history)
|
||||
hist_path = tmp_hist.name
|
||||
|
||||
# Run blame to get aider percentage
|
||||
blame_result = subprocess.run(["python3", "scripts/blame.py"], capture_output=True, text=True)
|
||||
aider_line = blame_result.stdout.strip().split("\n")[-1] # Get last line with percentage
|
||||
|
||||
# Construct and run the aider command
|
||||
message = f"""
|
||||
Update the history with changes shown in the diffs.
|
||||
Describe actual user-facing changes, not every single commit that was made implementing them.
|
||||
Don't edit or duplicate changes that have existing history entries, just add any new items not already listed.
|
||||
Be sure to attribute changes to the proper .x version.
|
||||
Changes in the .x-dev version should be listed under a "### main branch" heading
|
||||
|
||||
Also, add this as the last bullet under the "### main branch" section:
|
||||
{aider_line}
|
||||
""" # noqa
|
||||
|
||||
cmd = ["aider", hist_path, "--read", diff_path, "--msg", message, "--no-auto-commit"]
|
||||
subprocess.run(cmd)
|
||||
|
||||
# Read back the updated history
|
||||
with open(hist_path, "r") as f:
|
||||
updated_history = f.read()
|
||||
|
||||
# Find where the next version section would start
|
||||
if next_version_idx == -1:
|
||||
# No next version found, use the rest of the file
|
||||
full_history = history_content[:start_idx] + updated_history
|
||||
else:
|
||||
# Splice the updated portion back in between the unchanged parts
|
||||
full_history = (
|
||||
history_content[:start_idx]
|
||||
+ updated_history # Keep unchanged header
|
||||
+ history_content[next_version_idx:] # Add updated portion # Keep older entries
|
||||
)
|
||||
|
||||
# Write back the full history
|
||||
with open("HISTORY.md", "w") as f:
|
||||
f.write(full_history)
|
||||
|
||||
# Run update-docs.sh after aider
|
||||
subprocess.run(["scripts/update-docs.sh"])
|
||||
|
||||
# Cleanup
|
||||
os.unlink(diff_path)
|
||||
os.unlink(hist_path)
|
||||
|
||||
# Show git diff of HISTORY.md
|
||||
subprocess.run(["git", "diff", "HISTORY.md"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -124,7 +124,10 @@ def main():
|
||||
for cmd in git_commands:
|
||||
print(f"Running: {' '.join(cmd)}")
|
||||
if not dry_run:
|
||||
subprocess.run(cmd, check=True)
|
||||
subprocess.run(
|
||||
cmd,
|
||||
check=True,
|
||||
)
|
||||
|
||||
new_dev_version = f"{incremented_version}.dev"
|
||||
updated_dev_content = re.sub(
|
||||
|
||||
@@ -91,10 +91,49 @@ def test_system_info(temp_data_dir):
|
||||
|
||||
def test_need_to_ask(temp_data_dir):
|
||||
analytics = Analytics()
|
||||
assert analytics.need_to_ask() is True
|
||||
assert analytics.need_to_ask(True) is True
|
||||
assert analytics.need_to_ask(False) is False
|
||||
|
||||
analytics.user_id = "111"
|
||||
assert analytics.need_to_ask(None) is False
|
||||
|
||||
analytics.user_id = "000"
|
||||
assert analytics.need_to_ask(None) is True
|
||||
|
||||
analytics.asked_opt_in = True
|
||||
assert analytics.need_to_ask() is False
|
||||
assert analytics.need_to_ask(True) is False
|
||||
|
||||
analytics.permanently_disable = True
|
||||
assert analytics.need_to_ask() is False
|
||||
assert analytics.need_to_ask(True) is False
|
||||
|
||||
|
||||
def test_is_uuid_in_percentage():
|
||||
analytics = Analytics()
|
||||
|
||||
# Test basic percentage thresholds
|
||||
assert analytics.is_uuid_in_percentage("00000000000000000000000000000000", 1) is True
|
||||
assert analytics.is_uuid_in_percentage("01999000000000000000000000000000", 1) is True
|
||||
assert analytics.is_uuid_in_percentage("02000000000000000000000000000000", 1) is True
|
||||
assert analytics.is_uuid_in_percentage("02910000000000000000000000000001", 1) is False
|
||||
assert analytics.is_uuid_in_percentage("03000000000000000000000000000000", 1) is False
|
||||
assert analytics.is_uuid_in_percentage("ff000000000000000000000000000000", 1) is False
|
||||
|
||||
assert analytics.is_uuid_in_percentage("00000000000000000000000000000000", 10) is True
|
||||
assert analytics.is_uuid_in_percentage("19000000000000000000000000000000", 10) is True
|
||||
assert analytics.is_uuid_in_percentage("1a000000000000000000000000000000", 10) is False
|
||||
assert analytics.is_uuid_in_percentage("ff000000000000000000000000000000", 10) is False
|
||||
|
||||
# Test edge cases
|
||||
assert analytics.is_uuid_in_percentage("00000000000000000000000000000000", 0) is False
|
||||
assert analytics.is_uuid_in_percentage("00000000000000000000000000000000", 100) is True
|
||||
assert analytics.is_uuid_in_percentage("ffffffffffffffffffffffffffffffff", 100) is True
|
||||
|
||||
# Test invalid inputs
|
||||
with pytest.raises(ValueError):
|
||||
analytics.is_uuid_in_percentage("00000000000000000000000000000000", -1)
|
||||
with pytest.raises(ValueError):
|
||||
analytics.is_uuid_in_percentage("00000000000000000000000000000000", 101)
|
||||
|
||||
# Test empty/None UUID
|
||||
assert analytics.is_uuid_in_percentage("", 50) is False
|
||||
assert analytics.is_uuid_in_percentage(None, 50) is False
|
||||
|
||||
@@ -7,6 +7,7 @@ from unittest.mock import MagicMock, patch
|
||||
import git
|
||||
|
||||
from aider.coders import Coder
|
||||
from aider.coders.base_coder import UnknownEditFormat
|
||||
from aider.dump import dump # noqa: F401
|
||||
from aider.io import InputOutput
|
||||
from aider.models import Model
|
||||
@@ -168,6 +169,37 @@ class TestCoder(unittest.TestCase):
|
||||
|
||||
self.assertEqual(coder.abs_fnames, set([str(fname.resolve())]))
|
||||
|
||||
def test_skip_duplicate_basename_mentions(self):
|
||||
with GitTemporaryDirectory():
|
||||
io = InputOutput(pretty=False, yes=True)
|
||||
coder = Coder.create(self.GPT35, None, io)
|
||||
|
||||
# Create files with same basename in different directories
|
||||
fname1 = Path("dir1") / "file.txt"
|
||||
fname2 = Path("dir2") / "file.txt"
|
||||
fname3 = Path("dir3") / "unique.txt"
|
||||
|
||||
for fname in [fname1, fname2, fname3]:
|
||||
fname.parent.mkdir(parents=True, exist_ok=True)
|
||||
fname.touch()
|
||||
|
||||
# Add one file to chat
|
||||
coder.add_rel_fname(str(fname1))
|
||||
|
||||
# Mock get_tracked_files to return all files
|
||||
mock = MagicMock()
|
||||
mock.return_value = set([str(fname1), str(fname2), str(fname3)])
|
||||
coder.repo.get_tracked_files = mock
|
||||
|
||||
# Check that file mentions skip files with duplicate basenames
|
||||
mentioned = coder.get_file_mentions(f"Check {fname2} and {fname3}")
|
||||
self.assertEqual(mentioned, {str(fname3)})
|
||||
|
||||
# Add a read-only file with same basename
|
||||
coder.abs_read_only_fnames.add(str(fname2.resolve()))
|
||||
mentioned = coder.get_file_mentions(f"Check {fname1} and {fname3}")
|
||||
self.assertEqual(mentioned, {str(fname3)})
|
||||
|
||||
def test_check_for_file_mentions_read_only(self):
|
||||
with GitTemporaryDirectory():
|
||||
io = InputOutput(
|
||||
@@ -739,7 +771,7 @@ two
|
||||
# Test case with no URL
|
||||
no_url_input = "This text contains no URL"
|
||||
result = coder.check_for_urls(no_url_input)
|
||||
self.assertEqual(result, [])
|
||||
self.assertEqual(result, no_url_input)
|
||||
|
||||
# Test case with the same URL appearing multiple times
|
||||
repeated_url_input = (
|
||||
@@ -747,7 +779,8 @@ two
|
||||
" more time"
|
||||
)
|
||||
result = coder.check_for_urls(repeated_url_input)
|
||||
self.assertEqual(result.count("https://example.com"), 1)
|
||||
# the original 3 in the input text, plus 1 more for the scraped text
|
||||
self.assertEqual(result.count("https://example.com"), 4)
|
||||
self.assertIn("https://example.com", result)
|
||||
|
||||
def test_coder_from_coder_with_subdir(self):
|
||||
@@ -821,32 +854,55 @@ This command will print 'Hello, World!' to the console."""
|
||||
with GitTemporaryDirectory():
|
||||
io = InputOutput(yes=True)
|
||||
coder = Coder.create(self.GPT35, "diff", io=io, suggest_shell_commands=False)
|
||||
self.assertFalse(coder.suggest_shell_commands)
|
||||
|
||||
def mock_send(*args, **kwargs):
|
||||
coder.partial_response_content = """Here's a shell command to run:
|
||||
def test_detect_urls_enabled(self):
|
||||
with GitTemporaryDirectory():
|
||||
io = InputOutput(yes=True)
|
||||
coder = Coder.create(self.GPT35, "diff", io=io, detect_urls=True)
|
||||
coder.commands.scraper = MagicMock()
|
||||
coder.commands.scraper.scrape = MagicMock(return_value="some content")
|
||||
|
||||
```bash
|
||||
echo "Hello, World!"
|
||||
```
|
||||
# Test with a message containing a URL
|
||||
message = "Check out https://example.com"
|
||||
coder.check_for_urls(message)
|
||||
coder.commands.scraper.scrape.assert_called_once_with("https://example.com")
|
||||
|
||||
This command will print 'Hello, World!' to the console."""
|
||||
coder.partial_response_function_call = dict()
|
||||
return []
|
||||
def test_detect_urls_disabled(self):
|
||||
with GitTemporaryDirectory():
|
||||
io = InputOutput(yes=True)
|
||||
coder = Coder.create(self.GPT35, "diff", io=io, detect_urls=False)
|
||||
coder.commands.scraper = MagicMock()
|
||||
coder.commands.scraper.scrape = MagicMock(return_value="some content")
|
||||
|
||||
coder.send = mock_send
|
||||
# Test with a message containing a URL
|
||||
message = "Check out https://example.com"
|
||||
result = coder.check_for_urls(message)
|
||||
self.assertEqual(result, message)
|
||||
coder.commands.scraper.scrape.assert_not_called()
|
||||
|
||||
# Mock the handle_shell_commands method to check if it's called
|
||||
coder.handle_shell_commands = MagicMock()
|
||||
def test_unknown_edit_format_exception(self):
|
||||
# Test the exception message format
|
||||
invalid_format = "invalid_format"
|
||||
valid_formats = ["diff", "whole", "map"]
|
||||
exc = UnknownEditFormat(invalid_format, valid_formats)
|
||||
expected_msg = (
|
||||
f"Unknown edit format {invalid_format}. Valid formats are: {', '.join(valid_formats)}"
|
||||
)
|
||||
self.assertEqual(str(exc), expected_msg)
|
||||
|
||||
# Run the coder with a message
|
||||
coder.run(with_message="Suggest a shell command")
|
||||
def test_unknown_edit_format_creation(self):
|
||||
# Test that creating a Coder with invalid edit format raises the exception
|
||||
io = InputOutput(yes=True)
|
||||
invalid_format = "invalid_format"
|
||||
|
||||
# Check if the shell command was added to the list
|
||||
self.assertEqual(len(coder.shell_commands), 1)
|
||||
self.assertEqual(coder.shell_commands[0].strip(), 'echo "Hello, World!"')
|
||||
with self.assertRaises(UnknownEditFormat) as cm:
|
||||
Coder.create(self.GPT35, invalid_format, io=io)
|
||||
|
||||
# Check if handle_shell_commands was called with the correct argument
|
||||
coder.handle_shell_commands.assert_not_called()
|
||||
exc = cm.exception
|
||||
self.assertEqual(exc.edit_format, invalid_format)
|
||||
self.assertIsInstance(exc.valid_formats, list)
|
||||
self.assertTrue(len(exc.valid_formats) > 0)
|
||||
|
||||
def test_coder_create_with_new_file_oserror(self):
|
||||
with GitTemporaryDirectory():
|
||||
|
||||
@@ -236,7 +236,7 @@ class TestCommands(TestCase):
|
||||
self.assertIn(str(Path("test_dir/test_file2.txt").resolve()), coder.abs_fnames)
|
||||
self.assertIn(str(Path("test_dir/another_dir/test_file.txt").resolve()), coder.abs_fnames)
|
||||
|
||||
commands.cmd_drop("test_dir/another_dir")
|
||||
commands.cmd_drop(str(Path("test_dir/another_dir")))
|
||||
self.assertIn(str(Path("test_dir/test_file1.txt").resolve()), coder.abs_fnames)
|
||||
self.assertIn(str(Path("test_dir/test_file2.txt").resolve()), coder.abs_fnames)
|
||||
self.assertNotIn(
|
||||
@@ -272,6 +272,7 @@ class TestCommands(TestCase):
|
||||
coder = Coder.create(self.GPT35, None, io)
|
||||
commands = Commands(io, coder)
|
||||
|
||||
# Create test files in root and subdirectory
|
||||
subdir = Path("subdir")
|
||||
subdir.mkdir()
|
||||
(subdir / "subtest1.py").touch()
|
||||
@@ -279,17 +280,50 @@ class TestCommands(TestCase):
|
||||
|
||||
Path("test1.py").touch()
|
||||
Path("test2.py").touch()
|
||||
Path("test3.txt").touch()
|
||||
|
||||
# Add some files to the chat session
|
||||
# Add all Python files to the chat session
|
||||
commands.cmd_add("*.py")
|
||||
initial_count = len(coder.abs_fnames)
|
||||
self.assertEqual(initial_count, 2) # Only root .py files should be added
|
||||
|
||||
self.assertEqual(len(coder.abs_fnames), 2)
|
||||
|
||||
# Call the cmd_drop method with a glob pattern
|
||||
# Test dropping with glob pattern
|
||||
commands.cmd_drop("*2.py")
|
||||
|
||||
self.assertIn(str(Path("test1.py").resolve()), coder.abs_fnames)
|
||||
self.assertNotIn(str(Path("test2.py").resolve()), coder.abs_fnames)
|
||||
self.assertEqual(len(coder.abs_fnames), initial_count - 1)
|
||||
|
||||
def test_cmd_drop_without_glob(self):
|
||||
# Initialize the Commands and InputOutput objects
|
||||
io = InputOutput(pretty=False, fancy_input=False, yes=True)
|
||||
from aider.coders import Coder
|
||||
|
||||
coder = Coder.create(self.GPT35, None, io)
|
||||
commands = Commands(io, coder)
|
||||
|
||||
# Create test files
|
||||
test_files = ["file1.txt", "file2.txt", "file3.py"]
|
||||
for fname in test_files:
|
||||
Path(fname).touch()
|
||||
|
||||
# Add all files to the chat session
|
||||
for fname in test_files:
|
||||
commands.cmd_add(fname)
|
||||
|
||||
initial_count = len(coder.abs_fnames)
|
||||
self.assertEqual(initial_count, 3)
|
||||
|
||||
# Test dropping individual files without glob
|
||||
commands.cmd_drop("file1.txt")
|
||||
self.assertNotIn(str(Path("file1.txt").resolve()), coder.abs_fnames)
|
||||
self.assertIn(str(Path("file2.txt").resolve()), coder.abs_fnames)
|
||||
self.assertEqual(len(coder.abs_fnames), initial_count - 1)
|
||||
|
||||
# Test dropping multiple files without glob
|
||||
commands.cmd_drop("file2.txt file3.py")
|
||||
self.assertNotIn(str(Path("file2.txt").resolve()), coder.abs_fnames)
|
||||
self.assertNotIn(str(Path("file3.py").resolve()), coder.abs_fnames)
|
||||
self.assertEqual(len(coder.abs_fnames), 0)
|
||||
|
||||
def test_cmd_add_bad_encoding(self):
|
||||
# Initialize the Commands and InputOutput objects
|
||||
@@ -903,6 +937,23 @@ class TestCommands(TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
# Add a dummy message to ensure format_messages() works
|
||||
vision_coder.cur_messages = [{"role": "user", "content": "Check the image"}]
|
||||
|
||||
# Check that the image file appears in the messages
|
||||
messages = vision_coder.format_messages().all_messages()
|
||||
found_image = False
|
||||
for msg in messages:
|
||||
if msg.get("role") == "user" and "content" in msg:
|
||||
content = msg["content"]
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get("type") == "text":
|
||||
if "test_image.jpg" in item.get("text", ""):
|
||||
found_image = True
|
||||
break
|
||||
self.assertTrue(found_image, "Image file not found in messages to LLM")
|
||||
|
||||
def test_cmd_read_only_with_glob_pattern(self):
|
||||
with GitTemporaryDirectory() as repo_dir:
|
||||
io = InputOutput(pretty=False, fancy_input=False, yes=False)
|
||||
@@ -1068,8 +1119,10 @@ class TestCommands(TestCase):
|
||||
io.prompt_ask = lambda *args, **kwargs: "y"
|
||||
|
||||
# Test the cmd_run method with a command that should not raise an error
|
||||
result = commands.cmd_run("exit 1", add_on_nonzero_exit=True)
|
||||
self.assertIn("I ran this command", result)
|
||||
commands.cmd_run("exit 1", add_on_nonzero_exit=True)
|
||||
|
||||
# Check that the output was added to cur_messages
|
||||
self.assertTrue(any("exit 1" in msg["content"] for msg in coder.cur_messages))
|
||||
|
||||
def test_cmd_add_drop_untracked_files(self):
|
||||
with GitTemporaryDirectory():
|
||||
@@ -1378,6 +1431,43 @@ class TestCommands(TestCase):
|
||||
finally:
|
||||
os.unlink(external_file_path)
|
||||
|
||||
def test_cmd_drop_read_only_with_relative_path(self):
|
||||
with ChdirTemporaryDirectory() as repo_dir:
|
||||
test_file = Path("test_file.txt")
|
||||
test_file.write_text("Test content")
|
||||
|
||||
# Create a test file in a subdirectory
|
||||
subdir = Path(repo_dir) / "subdir"
|
||||
subdir.mkdir()
|
||||
os.chdir(subdir)
|
||||
|
||||
io = InputOutput(pretty=False, fancy_input=False, yes=False)
|
||||
coder = Coder.create(self.GPT35, None, io)
|
||||
commands = Commands(io, coder)
|
||||
|
||||
# Add the file as read-only using absolute path
|
||||
rel_path = str(Path("..") / "test_file.txt")
|
||||
commands.cmd_read_only(rel_path)
|
||||
self.assertEqual(len(coder.abs_read_only_fnames), 1)
|
||||
|
||||
# Try to drop using relative path from different working directories
|
||||
commands.cmd_drop("test_file.txt")
|
||||
self.assertEqual(len(coder.abs_read_only_fnames), 0)
|
||||
|
||||
# Add it again
|
||||
commands.cmd_read_only(rel_path)
|
||||
self.assertEqual(len(coder.abs_read_only_fnames), 1)
|
||||
|
||||
commands.cmd_drop(rel_path)
|
||||
self.assertEqual(len(coder.abs_read_only_fnames), 0)
|
||||
|
||||
# Add it one more time
|
||||
commands.cmd_read_only(rel_path)
|
||||
self.assertEqual(len(coder.abs_read_only_fnames), 1)
|
||||
|
||||
commands.cmd_drop("test_file.txt")
|
||||
self.assertEqual(len(coder.abs_read_only_fnames), 0)
|
||||
|
||||
def test_cmd_read_only_with_multiple_files(self):
|
||||
with GitTemporaryDirectory() as repo_dir:
|
||||
io = InputOutput(pretty=False, fancy_input=False, yes=False)
|
||||
|
||||
129
tests/basic/test_editor.py
Normal file
129
tests/basic/test_editor.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import os
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from aider.editor import (
|
||||
DEFAULT_EDITOR_NIX,
|
||||
DEFAULT_EDITOR_OS_X,
|
||||
DEFAULT_EDITOR_WINDOWS,
|
||||
discover_editor,
|
||||
get_environment_editor,
|
||||
pipe_editor,
|
||||
print_status_message,
|
||||
write_temp_file,
|
||||
)
|
||||
|
||||
|
||||
def test_get_environment_editor():
|
||||
# Test with no environment variables set
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert get_environment_editor("default") == "default"
|
||||
|
||||
# Test EDITOR precedence
|
||||
with patch.dict(os.environ, {"EDITOR": "vim"}):
|
||||
assert get_environment_editor() == "vim"
|
||||
|
||||
# Test VISUAL overrides EDITOR
|
||||
with patch.dict(os.environ, {"EDITOR": "vim", "VISUAL": "code"}):
|
||||
assert get_environment_editor() == "code"
|
||||
|
||||
|
||||
def test_discover_editor_defaults():
|
||||
with patch("platform.system") as mock_system:
|
||||
# Test Windows default
|
||||
mock_system.return_value = "Windows"
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert discover_editor() == [DEFAULT_EDITOR_WINDOWS]
|
||||
|
||||
# Test macOS default
|
||||
mock_system.return_value = "Darwin"
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert discover_editor() == [DEFAULT_EDITOR_OS_X]
|
||||
|
||||
# Test Linux default
|
||||
mock_system.return_value = "Linux"
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert discover_editor() == [DEFAULT_EDITOR_NIX]
|
||||
|
||||
|
||||
def test_write_temp_file():
|
||||
# Test basic file creation
|
||||
content = "test content"
|
||||
filepath = write_temp_file(content)
|
||||
assert os.path.exists(filepath)
|
||||
with open(filepath, "r") as f:
|
||||
assert f.read() == content
|
||||
os.remove(filepath)
|
||||
|
||||
# Test with suffix
|
||||
filepath = write_temp_file("content", suffix="txt")
|
||||
assert filepath.endswith(".txt")
|
||||
os.remove(filepath)
|
||||
|
||||
# Test with prefix
|
||||
filepath = write_temp_file("content", prefix="test_")
|
||||
assert os.path.basename(filepath).startswith("test_")
|
||||
os.remove(filepath)
|
||||
|
||||
|
||||
def test_print_status_message(capsys):
|
||||
# Test success message
|
||||
print_status_message(True, "Success!")
|
||||
captured = capsys.readouterr()
|
||||
assert "Success!" in captured.out
|
||||
|
||||
# Test failure message
|
||||
print_status_message(False, "Failed!")
|
||||
captured = capsys.readouterr()
|
||||
assert "Failed!" in captured.out
|
||||
|
||||
|
||||
def test_discover_editor_override():
|
||||
# Test editor override
|
||||
assert discover_editor("code") == ["code"]
|
||||
assert discover_editor('vim -c "set noswapfile"') == ["vim", "-c", "set noswapfile"]
|
||||
|
||||
# Test invalid editor command
|
||||
with pytest.raises(RuntimeError):
|
||||
discover_editor('vim "unclosed quote')
|
||||
|
||||
|
||||
def test_pipe_editor():
|
||||
# Test with default editor
|
||||
test_content = "Initial content"
|
||||
modified_content = "Modified content"
|
||||
|
||||
# Mock the file operations and editor call
|
||||
with (
|
||||
patch("aider.editor.write_temp_file") as mock_write,
|
||||
patch("builtins.open") as mock_open,
|
||||
patch("os.remove") as mock_remove,
|
||||
patch("subprocess.call") as mock_subprocess,
|
||||
):
|
||||
# Setup mocks
|
||||
mock_write.return_value = "temp.txt"
|
||||
mock_file = MagicMock()
|
||||
mock_file.__enter__.return_value.read.return_value = modified_content
|
||||
mock_open.return_value = mock_file
|
||||
|
||||
# Test with default editor
|
||||
result = pipe_editor(test_content)
|
||||
assert result == modified_content
|
||||
mock_write.assert_called_with(test_content, None)
|
||||
mock_subprocess.assert_called()
|
||||
|
||||
# Test with custom editor
|
||||
result = pipe_editor(test_content, editor="code")
|
||||
assert result == modified_content
|
||||
mock_subprocess.assert_called()
|
||||
|
||||
# Test with suffix
|
||||
result = pipe_editor(test_content, suffix="md")
|
||||
assert result == modified_content
|
||||
mock_write.assert_called_with(test_content, "md")
|
||||
|
||||
# Test cleanup on permission error
|
||||
mock_remove.side_effect = PermissionError
|
||||
result = pipe_editor(test_content)
|
||||
assert result == modified_content
|
||||
@@ -45,7 +45,7 @@ class TestMain(TestCase):
|
||||
self.webbrowser_patcher.stop()
|
||||
|
||||
def test_main_with_empty_dir_no_files_on_command(self):
|
||||
main(["--no-git", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--no-git", "--exit", "--yes"], input=DummyInput(), output=DummyOutput())
|
||||
|
||||
def test_main_with_emptqy_dir_new_file(self):
|
||||
main(["foo.txt", "--yes", "--no-git", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
@@ -332,7 +332,7 @@ class TestMain(TestCase):
|
||||
def test_false_vals_in_env_file(self):
|
||||
self.create_env_file(".env", "AIDER_SHOW_DIFFS=off")
|
||||
with patch("aider.coders.Coder.create") as MockCoder:
|
||||
main(["--no-git"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--no-git", "--yes"], input=DummyInput(), output=DummyOutput())
|
||||
MockCoder.assert_called_once()
|
||||
_, kwargs = MockCoder.call_args
|
||||
self.assertEqual(kwargs["show_diffs"], False)
|
||||
@@ -340,7 +340,7 @@ class TestMain(TestCase):
|
||||
def test_true_vals_in_env_file(self):
|
||||
self.create_env_file(".env", "AIDER_SHOW_DIFFS=on")
|
||||
with patch("aider.coders.Coder.create") as MockCoder:
|
||||
main(["--no-git"], input=DummyInput(), output=DummyOutput())
|
||||
main(["--no-git", "--yes"], input=DummyInput(), output=DummyOutput())
|
||||
MockCoder.assert_called_once()
|
||||
_, kwargs = MockCoder.call_args
|
||||
self.assertEqual(kwargs["show_diffs"], True)
|
||||
@@ -381,7 +381,11 @@ class TestMain(TestCase):
|
||||
def test_verbose_mode_lists_env_vars(self):
|
||||
self.create_env_file(".env", "AIDER_DARK_MODE=on")
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
main(["--no-git", "--verbose", "--exit"], input=DummyInput(), output=DummyOutput())
|
||||
main(
|
||||
["--no-git", "--verbose", "--exit", "--yes"],
|
||||
input=DummyInput(),
|
||||
output=DummyOutput(),
|
||||
)
|
||||
output = mock_stdout.getvalue()
|
||||
relevant_output = "\n".join(
|
||||
line
|
||||
@@ -633,6 +637,53 @@ class TestMain(TestCase):
|
||||
)
|
||||
self.assertTrue(coder.suggest_shell_commands)
|
||||
|
||||
def test_detect_urls_default(self):
|
||||
with GitTemporaryDirectory():
|
||||
coder = main(
|
||||
["--exit", "--yes"],
|
||||
input=DummyInput(),
|
||||
output=DummyOutput(),
|
||||
return_coder=True,
|
||||
)
|
||||
self.assertTrue(coder.detect_urls)
|
||||
|
||||
def test_detect_urls_disabled(self):
|
||||
with GitTemporaryDirectory():
|
||||
coder = main(
|
||||
["--no-detect-urls", "--exit", "--yes"],
|
||||
input=DummyInput(),
|
||||
output=DummyOutput(),
|
||||
return_coder=True,
|
||||
)
|
||||
self.assertFalse(coder.detect_urls)
|
||||
|
||||
def test_detect_urls_enabled(self):
|
||||
with GitTemporaryDirectory():
|
||||
coder = main(
|
||||
["--detect-urls", "--exit", "--yes"],
|
||||
input=DummyInput(),
|
||||
output=DummyOutput(),
|
||||
return_coder=True,
|
||||
)
|
||||
self.assertTrue(coder.detect_urls)
|
||||
|
||||
def test_pytest_env_vars(self):
|
||||
# Verify that environment variables from pytest.ini are properly set
|
||||
self.assertEqual(os.environ.get("AIDER_ANALYTICS"), "false")
|
||||
|
||||
def test_invalid_edit_format(self):
|
||||
with GitTemporaryDirectory():
|
||||
with patch("aider.io.InputOutput.offer_url") as mock_offer_url:
|
||||
result = main(
|
||||
["--edit-format", "not-a-real-format", "--exit", "--yes"],
|
||||
input=DummyInput(),
|
||||
output=DummyOutput(),
|
||||
)
|
||||
self.assertEqual(result, 1) # main() should return 1 on error
|
||||
mock_offer_url.assert_called_once()
|
||||
args, _ = mock_offer_url.call_args
|
||||
self.assertEqual(args[0], "https://aider.chat/docs/more/edit-formats.html")
|
||||
|
||||
def test_chat_language_spanish(self):
|
||||
with GitTemporaryDirectory():
|
||||
coder = main(
|
||||
|
||||
@@ -2,8 +2,10 @@ import unittest
|
||||
from unittest.mock import ANY, MagicMock, patch
|
||||
|
||||
from aider.models import (
|
||||
ANTHROPIC_BETA_HEADER,
|
||||
Model,
|
||||
ModelInfoManager,
|
||||
register_models,
|
||||
sanity_check_model,
|
||||
sanity_check_models,
|
||||
)
|
||||
@@ -80,7 +82,9 @@ class TestModels(unittest.TestCase):
|
||||
) # Should return True because there's a problem with the editor model
|
||||
mock_io.tool_warning.assert_called_with(ANY) # Ensure a warning was issued
|
||||
|
||||
warning_messages = [call.args[0] for call in mock_io.tool_warning.call_args_list]
|
||||
warning_messages = [
|
||||
warning_call.args[0] for warning_call in mock_io.tool_warning.call_args_list
|
||||
]
|
||||
print("Warning messages:", warning_messages) # Add this line
|
||||
|
||||
self.assertGreaterEqual(mock_io.tool_warning.call_count, 1) # Expect two warnings
|
||||
@@ -88,6 +92,87 @@ class TestModels(unittest.TestCase):
|
||||
any("bogus-model" in msg for msg in warning_messages)
|
||||
) # Check that one of the warnings mentions the bogus model
|
||||
|
||||
def test_model_aliases(self):
|
||||
# Test common aliases
|
||||
model = Model("4")
|
||||
self.assertEqual(model.name, "gpt-4-0613")
|
||||
|
||||
model = Model("4o")
|
||||
self.assertEqual(model.name, "gpt-4o-2024-08-06")
|
||||
|
||||
model = Model("35turbo")
|
||||
self.assertEqual(model.name, "gpt-3.5-turbo")
|
||||
|
||||
model = Model("35-turbo")
|
||||
self.assertEqual(model.name, "gpt-3.5-turbo")
|
||||
|
||||
model = Model("3")
|
||||
self.assertEqual(model.name, "gpt-3.5-turbo")
|
||||
|
||||
model = Model("sonnet")
|
||||
self.assertEqual(model.name, "claude-3-5-sonnet-20241022")
|
||||
|
||||
model = Model("haiku")
|
||||
self.assertEqual(model.name, "claude-3-5-haiku-20241022")
|
||||
|
||||
model = Model("opus")
|
||||
self.assertEqual(model.name, "claude-3-opus-20240229")
|
||||
|
||||
# Test non-alias passes through unchanged
|
||||
model = Model("gpt-4")
|
||||
self.assertEqual(model.name, "gpt-4")
|
||||
|
||||
def test_aider_extra_model_settings(self):
|
||||
import tempfile
|
||||
|
||||
import yaml
|
||||
|
||||
# Create temporary YAML file with test settings
|
||||
test_settings = [
|
||||
{
|
||||
"name": "aider/extra_params",
|
||||
"extra_params": {
|
||||
"extra_headers": {"Foo": "bar"},
|
||||
"some_param": "some value",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
# Write to a regular file instead of NamedTemporaryFile
|
||||
# for better cross-platform compatibility
|
||||
tmp = tempfile.mktemp(suffix=".yml")
|
||||
try:
|
||||
with open(tmp, "w") as f:
|
||||
yaml.dump(test_settings, f)
|
||||
|
||||
# Register the test settings
|
||||
register_models([tmp])
|
||||
|
||||
# Test that defaults are applied when no exact match
|
||||
model = Model("claude-3-5-sonnet-20240620")
|
||||
# Test that both the override and existing headers are present
|
||||
model = Model("claude-3-5-sonnet-20240620")
|
||||
self.assertEqual(model.extra_params["extra_headers"]["Foo"], "bar")
|
||||
self.assertEqual(
|
||||
model.extra_params["extra_headers"]["anthropic-beta"],
|
||||
ANTHROPIC_BETA_HEADER,
|
||||
)
|
||||
self.assertEqual(model.extra_params["some_param"], "some value")
|
||||
self.assertEqual(model.extra_params["max_tokens"], 8192)
|
||||
|
||||
# Test that exact match overrides defaults but not overrides
|
||||
model = Model("gpt-4")
|
||||
self.assertEqual(model.extra_params["extra_headers"]["Foo"], "bar")
|
||||
self.assertEqual(model.extra_params["some_param"], "some value")
|
||||
finally:
|
||||
# Clean up the temporary file
|
||||
import os
|
||||
|
||||
try:
|
||||
os.unlink(tmp)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -278,94 +278,6 @@ class TestRepoMapTypescript(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.GPT35 = Model("gpt-3.5-turbo")
|
||||
|
||||
def test_get_repo_map_typescript(self):
|
||||
# Create a temporary directory with a sample TypeScript file
|
||||
test_file_ts = "test_file.ts"
|
||||
file_content_ts = """\
|
||||
interface IMyInterface {
|
||||
someMethod(): void;
|
||||
}
|
||||
|
||||
type ExampleType = {
|
||||
key: string;
|
||||
value: number;
|
||||
};
|
||||
|
||||
enum Status {
|
||||
New,
|
||||
InProgress,
|
||||
Completed,
|
||||
}
|
||||
|
||||
export class MyClass {
|
||||
constructor(public value: number) {}
|
||||
|
||||
add(input: number): number {
|
||||
return this.value + input;
|
||||
return this.value + input;
|
||||
}
|
||||
}
|
||||
|
||||
export function myFunction(input: number): number {
|
||||
return input * 2;
|
||||
}
|
||||
"""
|
||||
|
||||
with IgnorantTemporaryDirectory() as temp_dir:
|
||||
with open(os.path.join(temp_dir, test_file_ts), "w") as f:
|
||||
f.write(file_content_ts)
|
||||
|
||||
io = InputOutput()
|
||||
repo_map = RepoMap(main_model=self.GPT35, root=temp_dir, io=io)
|
||||
other_files = [os.path.join(temp_dir, test_file_ts)]
|
||||
result = repo_map.get_repo_map([], other_files)
|
||||
|
||||
# Check if the result contains the expected tags map with TypeScript identifiers
|
||||
self.assertIn("test_file.ts", result)
|
||||
self.assertIn("IMyInterface", result)
|
||||
self.assertIn("ExampleType", result)
|
||||
self.assertIn("Status", result)
|
||||
self.assertIn("MyClass", result)
|
||||
self.assertIn("add", result)
|
||||
self.assertIn("myFunction", result)
|
||||
|
||||
# close the open cache files, so Windows won't error
|
||||
del repo_map
|
||||
|
||||
def test_get_repo_map_tsx(self):
|
||||
# Create a temporary directory with a sample TSX file
|
||||
test_file_tsx = "test_file.tsx"
|
||||
file_content_tsx = """\
|
||||
import React from 'react';
|
||||
|
||||
interface GreetingProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const Greeting: React.FC<GreetingProps> = ({ name }) => {
|
||||
return <h1>Hello, {name}!</h1>;
|
||||
};
|
||||
|
||||
export default Greeting;
|
||||
"""
|
||||
|
||||
with IgnorantTemporaryDirectory() as temp_dir:
|
||||
with open(os.path.join(temp_dir, test_file_tsx), "w") as f:
|
||||
f.write(file_content_tsx)
|
||||
|
||||
io = InputOutput()
|
||||
repo_map = RepoMap(main_model=self.GPT35, root=temp_dir, io=io)
|
||||
other_files = [os.path.join(temp_dir, test_file_tsx)]
|
||||
result = repo_map.get_repo_map([], other_files)
|
||||
|
||||
# Check if the result contains the expected tags map with TSX identifiers
|
||||
self.assertIn("test_file.tsx", result)
|
||||
self.assertIn("GreetingProps", result)
|
||||
self.assertIn("Greeting", result)
|
||||
|
||||
# close the open cache files, so Windows won't error
|
||||
del repo_map
|
||||
|
||||
|
||||
class TestRepoMapAllLanguages(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@@ -373,101 +285,69 @@ class TestRepoMapAllLanguages(unittest.TestCase):
|
||||
|
||||
def test_get_repo_map_all_languages(self):
|
||||
language_files = {
|
||||
"c": (
|
||||
"test.c",
|
||||
(
|
||||
'#include <stdio.h>\n\nint main() {\n printf("Hello, World!\\n");\n '
|
||||
" return 0;\n}\n"
|
||||
),
|
||||
),
|
||||
"csharp": (
|
||||
"test.cs",
|
||||
(
|
||||
"using System;\n\nclass Program {\n static void Main() {\n "
|
||||
' Console.WriteLine("Hello, World!");\n }\n}\n'
|
||||
),
|
||||
),
|
||||
"cpp": (
|
||||
"test.cpp",
|
||||
(
|
||||
'#include <iostream>\n\nint main() {\n std::cout << "Hello, World!" <<'
|
||||
" std::endl;\n return 0;\n}\n"
|
||||
),
|
||||
),
|
||||
"elisp": ("test.el", '(defun greet (name)\n (message "Hello, %s!" name))\n'),
|
||||
"elixir": (
|
||||
"test.ex",
|
||||
(
|
||||
'defmodule Greeter do\n def hello(name) do\n IO.puts("Hello, #{name}!")\n '
|
||||
" end\nend\n"
|
||||
),
|
||||
),
|
||||
"elm": (
|
||||
"test.elm",
|
||||
(
|
||||
"module Main exposing (main)\n\nimport Html exposing (text)\n\nmain =\n text"
|
||||
' "Hello, World!"\n'
|
||||
),
|
||||
),
|
||||
"go": (
|
||||
"test.go",
|
||||
(
|
||||
'package main\n\nimport "fmt"\n\nfunc main() {\n fmt.Println("Hello,'
|
||||
' World!")\n}\n'
|
||||
),
|
||||
),
|
||||
"java": (
|
||||
"Test.java",
|
||||
(
|
||||
"public class Test {\n public static void main(String[] args) {\n "
|
||||
' System.out.println("Hello, World!");\n }\n}\n'
|
||||
),
|
||||
),
|
||||
"javascript": (
|
||||
"test.js",
|
||||
"function greet(name) {\n console.log(`Hello, ${name}!`);\n}\n",
|
||||
),
|
||||
"ocaml": ("test.ml", 'let greet name =\n Printf.printf "Hello, %s!\\n" name\n'),
|
||||
"php": (
|
||||
"test.php",
|
||||
'<?php\nfunction greet($name) {\n echo "Hello, $name!";\n}\n?>\n',
|
||||
),
|
||||
"python": ("test.py", 'def greet(name):\n print(f"Hello, {name}!")\n'),
|
||||
"ql": ("test.ql", 'predicate greet(string name) {\n name = "World"\n}\n'),
|
||||
"ruby": ("test.rb", 'def greet(name)\n puts "Hello, #{name}!"\nend\n'),
|
||||
"rust": ("test.rs", 'fn main() {\n println!("Hello, World!");\n}\n'),
|
||||
"typescript": (
|
||||
"test.ts",
|
||||
"function greet(name: string): void {\n console.log(`Hello, ${name}!`);\n}\n",
|
||||
),
|
||||
"tsx": (
|
||||
"test.tsx",
|
||||
(
|
||||
"import React from 'react';\n\nconst Greeting: React.FC<{ name: string }> = ({"
|
||||
" name }) => {\n return <h1>Hello, {name}!</h1>;\n};\n\nexport default"
|
||||
" Greeting;\n"
|
||||
),
|
||||
),
|
||||
"c": ("c", "main"),
|
||||
"cpp": ("cpp", "main"),
|
||||
"elixir": ("ex", "Greeter"),
|
||||
"java": ("java", "Greeting"),
|
||||
"javascript": ("js", "Person"),
|
||||
"ocaml": ("ml", "Greeter"),
|
||||
"php": ("php", "greet"),
|
||||
"python": ("py", "Person"),
|
||||
"ql": ("ql", "greet"),
|
||||
"ruby": ("rb", "greet"),
|
||||
"rust": ("rs", "Person"),
|
||||
"typescript": ("ts", "greet"),
|
||||
"tsx": ("tsx", "UserProps"),
|
||||
"csharp": ("cs", "IGreeter"),
|
||||
"elisp": ("el", "greeter"),
|
||||
"elm": ("elm", "Person"),
|
||||
"go": ("go", "Greeter"),
|
||||
}
|
||||
|
||||
with IgnorantTemporaryDirectory() as temp_dir:
|
||||
for _, (filename, content) in language_files.items():
|
||||
with open(os.path.join(temp_dir, filename), "w") as f:
|
||||
fixtures_dir = Path(__file__).parent.parent / "fixtures" / "languages"
|
||||
|
||||
for lang, key_symbol in language_files.items():
|
||||
# Get the fixture file path and name based on language
|
||||
fixture_dir = fixtures_dir / lang
|
||||
ext, key_symbol = language_files[lang]
|
||||
filename = f"test.{ext}"
|
||||
fixture_path = fixture_dir / filename
|
||||
self.assertTrue(
|
||||
fixture_path.exists(), f"Fixture file missing for {lang}: {fixture_path}"
|
||||
)
|
||||
|
||||
# Read the fixture content
|
||||
with open(fixture_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
with GitTemporaryDirectory() as temp_dir:
|
||||
test_file = os.path.join(temp_dir, filename)
|
||||
with open(test_file, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
io = InputOutput()
|
||||
repo_map = RepoMap(main_model=self.GPT35, root=temp_dir, io=io)
|
||||
other_files = [
|
||||
os.path.join(temp_dir, filename) for filename, _ in language_files.values()
|
||||
]
|
||||
result = repo_map.get_repo_map([], other_files)
|
||||
io = InputOutput()
|
||||
repo_map = RepoMap(main_model=self.GPT35, root=temp_dir, io=io)
|
||||
other_files = [filename]
|
||||
result = repo_map.get_repo_map([], other_files)
|
||||
dump(lang)
|
||||
dump(result)
|
||||
|
||||
# Check if the result contains all the expected files
|
||||
for lang, (filename, _) in language_files.items():
|
||||
self.assertIn(filename, result, f"File for language {lang} not found in repo map")
|
||||
self.assertGreater(len(result.strip().splitlines()), 1)
|
||||
|
||||
# close the open cache files, so Windows won't error
|
||||
del repo_map
|
||||
# Check if the result contains all the expected files and symbols
|
||||
self.assertIn(
|
||||
filename, result, f"File for language {lang} not found in repo map: {result}"
|
||||
)
|
||||
self.assertIn(
|
||||
key_symbol,
|
||||
result,
|
||||
(
|
||||
f"Key symbol '{key_symbol}' for language {lang} not found in repo map:"
|
||||
f" {result}"
|
||||
),
|
||||
)
|
||||
|
||||
# close the open cache files, so Windows won't error
|
||||
del repo_map
|
||||
|
||||
def test_repo_map_sample_code_base(self):
|
||||
# Path to the sample code base
|
||||
|
||||
103
tests/basic/test_voice.py
Normal file
103
tests/basic/test_voice.py
Normal file
@@ -0,0 +1,103 @@
|
||||
import os
|
||||
import queue
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from aider.voice import SoundDeviceError, Voice
|
||||
|
||||
|
||||
# Mock the entire sounddevice module
|
||||
@pytest.fixture
|
||||
def mock_sounddevice():
|
||||
mock_sd = MagicMock()
|
||||
mock_sd.query_devices.return_value = [
|
||||
{"name": "test_device", "max_input_channels": 2},
|
||||
{"name": "another_device", "max_input_channels": 1},
|
||||
]
|
||||
with patch.dict("sys.modules", {"sounddevice": mock_sd}):
|
||||
yield mock_sd
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_soundfile():
|
||||
with patch("aider.voice.sf") as mock_sf:
|
||||
yield mock_sf
|
||||
|
||||
|
||||
def test_voice_init_default_device(mock_sounddevice):
|
||||
voice = Voice()
|
||||
assert voice.device_id is None
|
||||
assert voice.audio_format == "wav"
|
||||
assert voice.sd == mock_sounddevice
|
||||
|
||||
|
||||
def test_voice_init_specific_device(mock_sounddevice):
|
||||
voice = Voice(device_name="test_device")
|
||||
assert voice.device_id == 0
|
||||
assert voice.sd == mock_sounddevice
|
||||
|
||||
|
||||
def test_voice_init_invalid_device(mock_sounddevice):
|
||||
with pytest.raises(ValueError) as exc:
|
||||
Voice(device_name="nonexistent_device")
|
||||
assert "Device" in str(exc.value)
|
||||
assert "not found" in str(exc.value)
|
||||
|
||||
|
||||
def test_voice_init_invalid_format():
|
||||
with patch("aider.voice.sf", MagicMock()): # Need to mock sf to avoid SoundDeviceError
|
||||
with pytest.raises(ValueError) as exc:
|
||||
Voice(audio_format="invalid")
|
||||
assert "Unsupported audio format" in str(exc.value)
|
||||
|
||||
|
||||
def test_callback_processing():
|
||||
with patch("aider.voice.sf", MagicMock()): # Need to mock sf to avoid SoundDeviceError
|
||||
voice = Voice()
|
||||
voice.q = queue.Queue()
|
||||
|
||||
# Test with silence (low amplitude)
|
||||
test_data = np.zeros((1000, 1))
|
||||
voice.callback(test_data, None, None, None)
|
||||
assert voice.pct == 0.5 # When range is too small (<=0.001), pct is set to 0.5
|
||||
|
||||
# Test with loud signal (high amplitude)
|
||||
test_data = np.ones((1000, 1))
|
||||
voice.callback(test_data, None, None, None)
|
||||
assert voice.pct > 0.9
|
||||
|
||||
# Verify data is queued
|
||||
assert not voice.q.empty()
|
||||
|
||||
|
||||
def test_get_prompt():
|
||||
with patch("aider.voice.sf", MagicMock()): # Need to mock sf to avoid SoundDeviceError
|
||||
voice = Voice()
|
||||
voice.start_time = os.times().elapsed
|
||||
voice.pct = 0.5 # 50% volume level
|
||||
|
||||
prompt = voice.get_prompt()
|
||||
assert "Recording" in prompt
|
||||
assert "sec" in prompt
|
||||
assert "█" in prompt # Should contain some filled blocks
|
||||
assert "░" in prompt # Should contain some empty blocks
|
||||
|
||||
|
||||
def test_record_and_transcribe_keyboard_interrupt():
|
||||
with patch("aider.voice.sf", MagicMock()):
|
||||
voice = Voice()
|
||||
with patch.object(voice, "raw_record_and_transcribe", side_effect=KeyboardInterrupt()):
|
||||
result = voice.record_and_transcribe()
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_record_and_transcribe_device_error():
|
||||
with patch("aider.voice.sf", MagicMock()):
|
||||
voice = Voice()
|
||||
with patch.object(
|
||||
voice, "raw_record_and_transcribe", side_effect=SoundDeviceError("Test error")
|
||||
):
|
||||
result = voice.record_and_transcribe()
|
||||
assert result is None
|
||||
6
tests/fixtures/languages/c/test.c
vendored
Normal file
6
tests/fixtures/languages/c/test.c
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello, World!\n");
|
||||
return 0;
|
||||
}
|
||||
6
tests/fixtures/languages/cpp/test.cpp
vendored
Normal file
6
tests/fixtures/languages/cpp/test.cpp
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello, World!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
39
tests/fixtures/languages/csharp/test.cs
vendored
Normal file
39
tests/fixtures/languages/csharp/test.cs
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Greetings {
|
||||
public interface IGreeter {
|
||||
string Greet(string name);
|
||||
}
|
||||
|
||||
public class Person {
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
|
||||
public Person(string name, int age) {
|
||||
Name = name;
|
||||
Age = age;
|
||||
}
|
||||
}
|
||||
|
||||
public class FormalGreeter : IGreeter {
|
||||
private const string PREFIX = "Good day";
|
||||
private static readonly int MAX_AGE = 150;
|
||||
|
||||
public string Greet(string name) {
|
||||
return $"{PREFIX}, {name}!";
|
||||
}
|
||||
|
||||
public string GreetPerson(Person person) {
|
||||
return $"{PREFIX}, {person.Name} ({person.Age})!";
|
||||
}
|
||||
}
|
||||
|
||||
public class Program {
|
||||
static void Main() {
|
||||
var greeter = new FormalGreeter();
|
||||
var person = new Person("World", 42);
|
||||
Console.WriteLine(greeter.GreetPerson(person));
|
||||
}
|
||||
}
|
||||
}
|
||||
25
tests/fixtures/languages/elisp/test.el
vendored
Normal file
25
tests/fixtures/languages/elisp/test.el
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
(defvar *default-greeting* "Hello")
|
||||
(defvar *max-name-length* 50)
|
||||
|
||||
(defstruct person
|
||||
(name "Anonymous")
|
||||
(age 0))
|
||||
|
||||
(defclass greeter ()
|
||||
((prefix :initarg :prefix
|
||||
:accessor greeter-prefix
|
||||
:initform *default-greeting*)))
|
||||
|
||||
(defmethod greet ((g greeter) (p person))
|
||||
(format nil "~A, ~A! You are ~D years old."
|
||||
(greeter-prefix g)
|
||||
(person-name p)
|
||||
(person-age p)))
|
||||
|
||||
(defun create-formal-greeter ()
|
||||
(make-instance 'greeter :prefix "Good day"))
|
||||
|
||||
(defun main ()
|
||||
(let ((greeter (create-formal-greeter))
|
||||
(person (make-person :name "World" :age 42)))
|
||||
(message "%s" (greet greeter person))))
|
||||
5
tests/fixtures/languages/elixir/test.ex
vendored
Normal file
5
tests/fixtures/languages/elixir/test.ex
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
defmodule Greeter do
|
||||
def hello(name) do
|
||||
IO.puts("Hello, #{name}!")
|
||||
end
|
||||
end
|
||||
38
tests/fixtures/languages/elm/test.elm
vendored
Normal file
38
tests/fixtures/languages/elm/test.elm
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
module Main exposing (main, Person, Greeting)
|
||||
|
||||
import Html exposing (Html, div, text)
|
||||
import Html.Attributes exposing (class)
|
||||
|
||||
type alias Person =
|
||||
{ name : String
|
||||
, age : Int
|
||||
}
|
||||
|
||||
type Greeting
|
||||
= Formal
|
||||
| Casual
|
||||
|
||||
greet : Greeting -> Person -> String
|
||||
greet style person =
|
||||
let
|
||||
prefix =
|
||||
case style of
|
||||
Formal ->
|
||||
"Good day"
|
||||
|
||||
Casual ->
|
||||
"Hi"
|
||||
in
|
||||
prefix ++ ", " ++ person.name ++ "!"
|
||||
|
||||
defaultPerson : Person
|
||||
defaultPerson =
|
||||
{ name = "World"
|
||||
, age = 42
|
||||
}
|
||||
|
||||
main : Html msg
|
||||
main =
|
||||
div [ class "greeting" ]
|
||||
[ text (greet Formal defaultPerson)
|
||||
]
|
||||
42
tests/fixtures/languages/go/test.go
vendored
Normal file
42
tests/fixtures/languages/go/test.go
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Person represents someone who can be greeted
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// Greeter defines greeting behavior
|
||||
type Greeter interface {
|
||||
Greet(p Person) string
|
||||
}
|
||||
|
||||
// FormalGreeter implements Greeter with formal style
|
||||
type FormalGreeter struct {
|
||||
Prefix string
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultName = "World"
|
||||
MaxAge = 150
|
||||
)
|
||||
|
||||
func (g FormalGreeter) Greet(p Person) string {
|
||||
return fmt.Sprintf("%s, %s! You are %d years old.",
|
||||
g.Prefix, p.Name, p.Age)
|
||||
}
|
||||
|
||||
func NewFormalGreeter() *FormalGreeter {
|
||||
return &FormalGreeter{Prefix: "Good day"}
|
||||
}
|
||||
|
||||
func main() {
|
||||
greeter := NewFormalGreeter()
|
||||
person := Person{Name: DefaultName, Age: 42}
|
||||
fmt.Println(greeter.Greet(person))
|
||||
}
|
||||
16
tests/fixtures/languages/java/test.java
vendored
Normal file
16
tests/fixtures/languages/java/test.java
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
public interface Greeting {
|
||||
String greet(String name);
|
||||
}
|
||||
|
||||
public class Test implements Greeting {
|
||||
private String prefix = "Hello";
|
||||
|
||||
public String greet(String name) {
|
||||
return prefix + ", " + name + "!";
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Test greeter = new Test();
|
||||
System.out.println(greeter.greet("World"));
|
||||
}
|
||||
}
|
||||
26
tests/fixtures/languages/javascript/test.js
vendored
Normal file
26
tests/fixtures/languages/javascript/test.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// Class definition
|
||||
class Person {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
sayHello() {
|
||||
return `Hello, ${this.name}!`;
|
||||
}
|
||||
}
|
||||
|
||||
// Function declaration
|
||||
function greet(person) {
|
||||
return person.sayHello();
|
||||
}
|
||||
|
||||
// Variables and constants
|
||||
const DEFAULT_NAME = 'World';
|
||||
let currentPerson = new Person(DEFAULT_NAME);
|
||||
|
||||
// Export for use in other modules
|
||||
module.exports = {
|
||||
Person,
|
||||
greet,
|
||||
DEFAULT_NAME
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user