aider-ce 0.88.20__py3-none-any.whl → 0.88.38__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aider/__init__.py +1 -1
- aider/_version.py +2 -2
- aider/args.py +63 -43
- aider/coders/agent_coder.py +331 -79
- aider/coders/agent_prompts.py +3 -15
- aider/coders/architect_coder.py +21 -5
- aider/coders/base_coder.py +661 -413
- aider/coders/base_prompts.py +6 -3
- aider/coders/chat_chunks.py +39 -17
- aider/commands.py +79 -15
- aider/diffs.py +10 -9
- aider/exceptions.py +1 -1
- aider/helpers/coroutines.py +8 -0
- aider/helpers/requests.py +45 -0
- aider/history.py +5 -0
- aider/io.py +179 -25
- aider/main.py +86 -35
- aider/models.py +16 -8
- aider/queries/tree-sitter-language-pack/c-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/clojure-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/commonlisp-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/cpp-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/csharp-tags.scm +6 -0
- aider/queries/tree-sitter-language-pack/dart-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/elixir-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/elm-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/go-tags.scm +7 -0
- aider/queries/tree-sitter-language-pack/java-tags.scm +6 -0
- aider/queries/tree-sitter-language-pack/javascript-tags.scm +8 -0
- aider/queries/tree-sitter-language-pack/lua-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/python-tags.scm +10 -0
- aider/queries/tree-sitter-language-pack/r-tags.scm +6 -0
- aider/queries/tree-sitter-language-pack/ruby-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/rust-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/solidity-tags.scm +1 -1
- aider/queries/tree-sitter-language-pack/swift-tags.scm +4 -1
- aider/queries/tree-sitter-languages/c-tags.scm +3 -0
- aider/queries/tree-sitter-languages/c_sharp-tags.scm +6 -0
- aider/queries/tree-sitter-languages/cpp-tags.scm +3 -0
- aider/queries/tree-sitter-languages/dart-tags.scm +2 -1
- aider/queries/tree-sitter-languages/elixir-tags.scm +5 -0
- aider/queries/tree-sitter-languages/elm-tags.scm +3 -0
- aider/queries/tree-sitter-languages/fortran-tags.scm +3 -0
- aider/queries/tree-sitter-languages/go-tags.scm +6 -0
- aider/queries/tree-sitter-languages/haskell-tags.scm +2 -0
- aider/queries/tree-sitter-languages/java-tags.scm +6 -0
- aider/queries/tree-sitter-languages/javascript-tags.scm +8 -0
- aider/queries/tree-sitter-languages/julia-tags.scm +2 -2
- aider/queries/tree-sitter-languages/kotlin-tags.scm +3 -0
- aider/queries/tree-sitter-languages/ocaml_interface-tags.scm +6 -0
- aider/queries/tree-sitter-languages/php-tags.scm +6 -0
- aider/queries/tree-sitter-languages/python-tags.scm +10 -0
- aider/queries/tree-sitter-languages/ruby-tags.scm +5 -0
- aider/queries/tree-sitter-languages/rust-tags.scm +3 -0
- aider/queries/tree-sitter-languages/scala-tags.scm +2 -3
- aider/queries/tree-sitter-languages/typescript-tags.scm +3 -0
- aider/queries/tree-sitter-languages/zig-tags.scm +20 -3
- aider/repomap.py +71 -11
- aider/resources/model-metadata.json +27335 -635
- aider/resources/model-settings.yml +190 -0
- aider/scrape.py +2 -0
- aider/tools/__init__.py +2 -0
- aider/tools/command.py +84 -94
- aider/tools/command_interactive.py +95 -110
- aider/tools/delete_block.py +131 -159
- aider/tools/delete_line.py +97 -132
- aider/tools/delete_lines.py +120 -160
- aider/tools/extract_lines.py +288 -312
- aider/tools/finished.py +30 -43
- aider/tools/git_branch.py +107 -109
- aider/tools/git_diff.py +44 -56
- aider/tools/git_log.py +39 -53
- aider/tools/git_remote.py +37 -51
- aider/tools/git_show.py +33 -47
- aider/tools/git_status.py +30 -44
- aider/tools/grep.py +214 -242
- aider/tools/indent_lines.py +175 -201
- aider/tools/insert_block.py +220 -253
- aider/tools/list_changes.py +65 -80
- aider/tools/ls.py +64 -80
- aider/tools/make_editable.py +57 -73
- aider/tools/make_readonly.py +50 -66
- aider/tools/remove.py +64 -80
- aider/tools/replace_all.py +96 -109
- aider/tools/replace_line.py +118 -156
- aider/tools/replace_lines.py +160 -197
- aider/tools/replace_text.py +159 -160
- aider/tools/show_numbered_context.py +115 -141
- aider/tools/thinking.py +52 -0
- aider/tools/undo_change.py +78 -91
- aider/tools/update_todo_list.py +130 -138
- aider/tools/utils/base_tool.py +64 -0
- aider/tools/utils/output.py +118 -0
- aider/tools/view.py +38 -54
- aider/tools/view_files_matching.py +131 -134
- aider/tools/view_files_with_symbol.py +108 -120
- aider/urls.py +1 -1
- aider/versioncheck.py +4 -3
- aider/website/docs/config/adv-model-settings.md +237 -0
- aider/website/docs/config/agent-mode.md +36 -3
- aider/website/docs/config/model-aliases.md +2 -1
- aider/website/docs/faq.md +6 -11
- aider/website/docs/languages.md +2 -2
- aider/website/docs/more/infinite-output.md +27 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/METADATA +112 -70
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/RECORD +112 -107
- aider_ce-0.88.38.dist-info/entry_points.txt +6 -0
- aider_ce-0.88.20.dist-info/entry_points.txt +0 -2
- /aider/tools/{tool_utils.py → utils/helpers.py} +0 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/WHEEL +0 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/licenses/LICENSE.txt +0 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/top_level.txt +0 -0
aider/main.py
CHANGED
|
@@ -353,6 +353,13 @@ def register_models(git_root, model_settings_fname, io, verbose=False):
|
|
|
353
353
|
io.tool_output(f" - {file_loaded}") # noqa: E221
|
|
354
354
|
elif verbose:
|
|
355
355
|
io.tool_output("No model settings files loaded")
|
|
356
|
+
|
|
357
|
+
if (
|
|
358
|
+
model_settings_fname
|
|
359
|
+
and model_settings_fname not in files_loaded
|
|
360
|
+
and model_settings_fname != ".aider.model.settings.yml"
|
|
361
|
+
):
|
|
362
|
+
io.tool_warning(f"Model Settings File Not Found: {model_settings_fname}")
|
|
356
363
|
except Exception as e:
|
|
357
364
|
io.tool_error(f"Error loading aider model settings: {e}")
|
|
358
365
|
return 1
|
|
@@ -411,6 +418,13 @@ def register_litellm_models(git_root, model_metadata_fname, io, verbose=False):
|
|
|
411
418
|
io.tool_output("Loaded model metadata from:")
|
|
412
419
|
for model_metadata_file in model_metadata_files_loaded:
|
|
413
420
|
io.tool_output(f" - {model_metadata_file}") # noqa: E221
|
|
421
|
+
|
|
422
|
+
if (
|
|
423
|
+
model_metadata_fname
|
|
424
|
+
and model_metadata_fname not in model_metadata_files_loaded
|
|
425
|
+
and model_metadata_fname != ".aider.model.metadata.json"
|
|
426
|
+
):
|
|
427
|
+
io.tool_warning(f"Model Metadata File Not Found: {model_metadata_fname}")
|
|
414
428
|
except Exception as e:
|
|
415
429
|
io.tool_error(f"Error loading model metadata models: {e}")
|
|
416
430
|
return 1
|
|
@@ -478,10 +492,27 @@ def expand_glob_patterns(patterns, root="."):
|
|
|
478
492
|
|
|
479
493
|
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
|
|
480
494
|
log_file = None
|
|
481
|
-
file_excludelist =
|
|
495
|
+
file_excludelist = {
|
|
496
|
+
"get_bottom_toolbar": True,
|
|
497
|
+
"<genexpr>": True,
|
|
498
|
+
"is_active": True,
|
|
499
|
+
"auto_save_session": True,
|
|
500
|
+
"input_task": True,
|
|
501
|
+
"output_task": True,
|
|
502
|
+
}
|
|
482
503
|
|
|
483
504
|
|
|
484
505
|
def custom_tracer(frame, event, arg):
|
|
506
|
+
try:
|
|
507
|
+
import os
|
|
508
|
+
except Exception:
|
|
509
|
+
return None
|
|
510
|
+
|
|
511
|
+
global log_file
|
|
512
|
+
if not log_file:
|
|
513
|
+
os.makedirs(".aider/logs/", exist_ok=True)
|
|
514
|
+
log_file = open(".aider/logs/debug.log", "w", buffering=1)
|
|
515
|
+
|
|
485
516
|
# Get the absolute path of the file where the code is executing
|
|
486
517
|
filename = os.path.abspath(frame.f_code.co_filename)
|
|
487
518
|
|
|
@@ -556,7 +587,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
556
587
|
except AttributeError as e:
|
|
557
588
|
if all(word in str(e) for word in ["bool", "object", "has", "no", "attribute", "strip"]):
|
|
558
589
|
if check_config_files_for_yes(default_config_files):
|
|
559
|
-
return 1
|
|
590
|
+
return await graceful_exit(None, 1)
|
|
560
591
|
raise e
|
|
561
592
|
|
|
562
593
|
if args.verbose:
|
|
@@ -588,7 +619,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
588
619
|
# Ensure parser.prog is set for shtab, though it should be by default
|
|
589
620
|
parser.prog = "aider"
|
|
590
621
|
print(shtab.complete(parser, shell=args.shell_completions))
|
|
591
|
-
|
|
622
|
+
return await graceful_exit(None, 0)
|
|
592
623
|
|
|
593
624
|
if git is None:
|
|
594
625
|
args.git = False
|
|
@@ -677,7 +708,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
677
708
|
except ValueError:
|
|
678
709
|
io.tool_error(f"Invalid --set-env format: {env_setting}")
|
|
679
710
|
io.tool_output("Format should be: ENV_VAR_NAME=value")
|
|
680
|
-
return 1
|
|
711
|
+
return await graceful_exit(None, 1)
|
|
681
712
|
|
|
682
713
|
# Process any API keys set via --api-key
|
|
683
714
|
if args.api_key:
|
|
@@ -689,7 +720,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
689
720
|
except ValueError:
|
|
690
721
|
io.tool_error(f"Invalid --api-key format: {api_setting}")
|
|
691
722
|
io.tool_output("Format should be: provider=key")
|
|
692
|
-
return 1
|
|
723
|
+
return await graceful_exit(None, 1)
|
|
693
724
|
|
|
694
725
|
if args.anthropic_api_key:
|
|
695
726
|
os.environ["ANTHROPIC_API_KEY"] = args.anthropic_api_key
|
|
@@ -747,11 +778,11 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
747
778
|
if args.gui and not return_coder:
|
|
748
779
|
if not await check_streamlit_install(io):
|
|
749
780
|
analytics.event("exit", reason="Streamlit not installed")
|
|
750
|
-
return
|
|
781
|
+
return await graceful_exit(None)
|
|
751
782
|
analytics.event("gui session")
|
|
752
783
|
launch_gui(argv)
|
|
753
784
|
analytics.event("exit", reason="GUI session ended")
|
|
754
|
-
return
|
|
785
|
+
return await graceful_exit(None)
|
|
755
786
|
|
|
756
787
|
if args.verbose:
|
|
757
788
|
for fname in loaded_dotenvs:
|
|
@@ -784,7 +815,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
784
815
|
"Provide either a single directory of a git repo, or a list of one or more files."
|
|
785
816
|
)
|
|
786
817
|
analytics.event("exit", reason="Invalid directory input")
|
|
787
|
-
return 1
|
|
818
|
+
return await graceful_exit(None, 1)
|
|
788
819
|
|
|
789
820
|
git_dname = None
|
|
790
821
|
if len(all_files) == 1:
|
|
@@ -795,7 +826,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
795
826
|
else:
|
|
796
827
|
io.tool_error(f"{all_files[0]} is a directory, but --no-git selected.")
|
|
797
828
|
analytics.event("exit", reason="Directory with --no-git")
|
|
798
|
-
return 1
|
|
829
|
+
return await graceful_exit(None, 1)
|
|
799
830
|
|
|
800
831
|
# We can't know the git repo for sure until after parsing the args.
|
|
801
832
|
# If we guessed wrong, reparse because that changes things like
|
|
@@ -809,17 +840,17 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
809
840
|
if args.just_check_update:
|
|
810
841
|
update_available = await check_version(io, just_check=True, verbose=args.verbose)
|
|
811
842
|
analytics.event("exit", reason="Just checking update")
|
|
812
|
-
return 0 if not update_available else 1
|
|
843
|
+
return await graceful_exit(None, 0 if not update_available else 1)
|
|
813
844
|
|
|
814
845
|
if args.install_main_branch:
|
|
815
846
|
success = await install_from_main_branch(io)
|
|
816
847
|
analytics.event("exit", reason="Installed main branch")
|
|
817
|
-
return 0 if success else 1
|
|
848
|
+
return await graceful_exit(None, 0 if success else 1)
|
|
818
849
|
|
|
819
850
|
if args.upgrade:
|
|
820
851
|
success = await install_upgrade(io)
|
|
821
852
|
analytics.event("exit", reason="Upgrade completed")
|
|
822
|
-
return 0 if success else 1
|
|
853
|
+
return await graceful_exit(None, 0 if success else 1)
|
|
823
854
|
|
|
824
855
|
if args.check_update:
|
|
825
856
|
await check_version(io, verbose=args.verbose)
|
|
@@ -841,7 +872,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
841
872
|
if args.list_models:
|
|
842
873
|
models.print_matching_models(io, args.list_models)
|
|
843
874
|
analytics.event("exit", reason="Listed models")
|
|
844
|
-
return
|
|
875
|
+
return await graceful_exit(None)
|
|
845
876
|
|
|
846
877
|
# Process any command line aliases
|
|
847
878
|
if args.alias:
|
|
@@ -852,7 +883,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
852
883
|
io.tool_error(f"Invalid alias format: {alias_def}")
|
|
853
884
|
io.tool_output("Format should be: alias:model-name")
|
|
854
885
|
analytics.event("exit", reason="Invalid alias format error")
|
|
855
|
-
return 1
|
|
886
|
+
return await graceful_exit(None, 1)
|
|
856
887
|
alias, model = parts
|
|
857
888
|
models.MODEL_ALIASES[alias.strip()] = model.strip()
|
|
858
889
|
|
|
@@ -861,7 +892,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
861
892
|
# Error message and analytics event are handled within select_default_model
|
|
862
893
|
# It might have already offered OAuth if no model/keys were found.
|
|
863
894
|
# If it failed here, we exit.
|
|
864
|
-
return 1
|
|
895
|
+
return await graceful_exit(None, 1)
|
|
865
896
|
args.model = selected_model_name # Update args with the selected model
|
|
866
897
|
|
|
867
898
|
# Check if an OpenRouter model was selected/specified but the key is missing
|
|
@@ -888,7 +919,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
888
919
|
"exit",
|
|
889
920
|
reason="OpenRouter key missing after successful OAuth for specified model",
|
|
890
921
|
)
|
|
891
|
-
return 1
|
|
922
|
+
return await graceful_exit(None, 1)
|
|
892
923
|
else:
|
|
893
924
|
# OAuth failed or was declined by the user
|
|
894
925
|
io.tool_error(
|
|
@@ -901,7 +932,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
901
932
|
"exit",
|
|
902
933
|
reason="OpenRouter key missing for specified model and OAuth failed/declined",
|
|
903
934
|
)
|
|
904
|
-
return 1
|
|
935
|
+
return await graceful_exit(None, 1)
|
|
905
936
|
|
|
906
937
|
main_model = models.Model(
|
|
907
938
|
args.model,
|
|
@@ -969,7 +1000,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
969
1000
|
lint_cmds = parse_lint_cmds(args.lint_cmd, io)
|
|
970
1001
|
if lint_cmds is None:
|
|
971
1002
|
analytics.event("exit", reason="Invalid lint command format")
|
|
972
|
-
return 1
|
|
1003
|
+
return await graceful_exit(None, 1)
|
|
973
1004
|
|
|
974
1005
|
repo = None
|
|
975
1006
|
if args.git:
|
|
@@ -995,7 +1026,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
995
1026
|
if not args.skip_sanity_check_repo:
|
|
996
1027
|
if not await sanity_check_repo(repo, io):
|
|
997
1028
|
analytics.event("exit", reason="Repository sanity check failed")
|
|
998
|
-
return 1
|
|
1029
|
+
return await graceful_exit(None, 1)
|
|
999
1030
|
|
|
1000
1031
|
if repo and not args.skip_sanity_check_repo:
|
|
1001
1032
|
num_files = len(repo.get_tracked_files())
|
|
@@ -1116,7 +1147,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
1116
1147
|
io.tool_output()
|
|
1117
1148
|
except KeyboardInterrupt:
|
|
1118
1149
|
analytics.event("exit", reason="Keyboard interrupt during model warnings")
|
|
1119
|
-
return 1
|
|
1150
|
+
return await graceful_exit(coder, 1)
|
|
1120
1151
|
|
|
1121
1152
|
if args.git:
|
|
1122
1153
|
git_root = await setup_git(git_root, io)
|
|
@@ -1129,11 +1160,12 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
1129
1160
|
urls.edit_formats, "Open documentation about edit formats?", acknowledge=True
|
|
1130
1161
|
)
|
|
1131
1162
|
analytics.event("exit", reason="Unknown edit format")
|
|
1132
|
-
return 1
|
|
1163
|
+
return await graceful_exit(None, 1)
|
|
1164
|
+
|
|
1133
1165
|
except ValueError as err:
|
|
1134
1166
|
io.tool_error(str(err))
|
|
1135
1167
|
analytics.event("exit", reason="ValueError during coder creation")
|
|
1136
|
-
return 1
|
|
1168
|
+
return await graceful_exit(None, 1)
|
|
1137
1169
|
|
|
1138
1170
|
if return_coder:
|
|
1139
1171
|
analytics.event("exit", reason="Returning coder object")
|
|
@@ -1166,7 +1198,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
1166
1198
|
messages = coder.format_messages().all_messages()
|
|
1167
1199
|
utils.show_messages(messages)
|
|
1168
1200
|
analytics.event("exit", reason="Showed prompts")
|
|
1169
|
-
return
|
|
1201
|
+
return await graceful_exit(coder)
|
|
1170
1202
|
|
|
1171
1203
|
if args.lint:
|
|
1172
1204
|
await coder.commands.cmd_lint(fnames=fnames)
|
|
@@ -1175,7 +1207,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
1175
1207
|
if not args.test_cmd:
|
|
1176
1208
|
io.tool_error("No --test-cmd provided.")
|
|
1177
1209
|
analytics.event("exit", reason="No test command provided")
|
|
1178
|
-
return 1
|
|
1210
|
+
return await graceful_exit(coder, 1)
|
|
1179
1211
|
await coder.commands.cmd_test(args.test_cmd)
|
|
1180
1212
|
if io.placeholder:
|
|
1181
1213
|
await coder.run(io.placeholder)
|
|
@@ -1188,27 +1220,27 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
1188
1220
|
|
|
1189
1221
|
if args.lint or args.test or args.commit:
|
|
1190
1222
|
analytics.event("exit", reason="Completed lint/test/commit")
|
|
1191
|
-
return
|
|
1223
|
+
return await graceful_exit(coder)
|
|
1192
1224
|
|
|
1193
1225
|
if args.show_repo_map:
|
|
1194
1226
|
repo_map = coder.get_repo_map()
|
|
1195
1227
|
if repo_map:
|
|
1196
1228
|
io.tool_output(repo_map)
|
|
1197
1229
|
analytics.event("exit", reason="Showed repo map")
|
|
1198
|
-
return
|
|
1230
|
+
return await graceful_exit(coder)
|
|
1199
1231
|
|
|
1200
1232
|
if args.apply:
|
|
1201
1233
|
content = io.read_text(args.apply)
|
|
1202
1234
|
if content is None:
|
|
1203
1235
|
analytics.event("exit", reason="Failed to read apply content")
|
|
1204
|
-
return
|
|
1236
|
+
return await graceful_exit(coder)
|
|
1205
1237
|
coder.partial_response_content = content
|
|
1206
1238
|
# For testing #2879
|
|
1207
1239
|
# from aider.coders.base_coder import all_fences
|
|
1208
1240
|
# coder.fence = all_fences[1]
|
|
1209
1241
|
await coder.apply_updates()
|
|
1210
1242
|
analytics.event("exit", reason="Applied updates")
|
|
1211
|
-
return
|
|
1243
|
+
return await graceful_exit(coder)
|
|
1212
1244
|
|
|
1213
1245
|
if args.apply_clipboard_edits:
|
|
1214
1246
|
args.edit_format = main_model.editor_edit_format
|
|
@@ -1250,7 +1282,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
1250
1282
|
except (SwitchCoder, KeyboardInterrupt, SystemExit):
|
|
1251
1283
|
pass
|
|
1252
1284
|
analytics.event("exit", reason="Completed --message")
|
|
1253
|
-
return
|
|
1285
|
+
return await graceful_exit(coder)
|
|
1254
1286
|
|
|
1255
1287
|
if args.message_file:
|
|
1256
1288
|
try:
|
|
@@ -1262,18 +1294,18 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
1262
1294
|
except FileNotFoundError:
|
|
1263
1295
|
io.tool_error(f"Message file not found: {args.message_file}")
|
|
1264
1296
|
analytics.event("exit", reason="Message file not found")
|
|
1265
|
-
return 1
|
|
1297
|
+
return await graceful_exit(coder, 1)
|
|
1266
1298
|
except IOError as e:
|
|
1267
1299
|
io.tool_error(f"Error reading message file: {e}")
|
|
1268
1300
|
analytics.event("exit", reason="Message file IO error")
|
|
1269
|
-
return 1
|
|
1301
|
+
return await graceful_exit(coder, 1)
|
|
1270
1302
|
|
|
1271
1303
|
analytics.event("exit", reason="Completed --message-file")
|
|
1272
|
-
return
|
|
1304
|
+
return await graceful_exit(coder)
|
|
1273
1305
|
|
|
1274
1306
|
if args.exit:
|
|
1275
1307
|
analytics.event("exit", reason="Exit flag set")
|
|
1276
|
-
return
|
|
1308
|
+
return await graceful_exit(coder)
|
|
1277
1309
|
|
|
1278
1310
|
analytics.event("cli session", main_model=main_model, edit_format=main_model.edit_format)
|
|
1279
1311
|
|
|
@@ -1293,7 +1325,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
1293
1325
|
coder.ok_to_warm_cache = bool(args.cache_keepalive_pings)
|
|
1294
1326
|
await coder.run()
|
|
1295
1327
|
analytics.event("exit", reason="Completed main CLI coder.run")
|
|
1296
|
-
return
|
|
1328
|
+
return await graceful_exit(coder)
|
|
1297
1329
|
except SwitchCoder as switch:
|
|
1298
1330
|
coder.ok_to_warm_cache = False
|
|
1299
1331
|
|
|
@@ -1316,7 +1348,8 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
|
|
|
1316
1348
|
coder.suppress_announcements_for_next_prompt = True
|
|
1317
1349
|
except SystemExit:
|
|
1318
1350
|
analytics.event("exit", reason="/exit command")
|
|
1319
|
-
|
|
1351
|
+
sys.settrace(None)
|
|
1352
|
+
return await graceful_exit(coder)
|
|
1320
1353
|
|
|
1321
1354
|
|
|
1322
1355
|
def is_first_run_of_new_version(io, verbose=False):
|
|
@@ -1410,6 +1443,24 @@ def load_slow_imports(swallow=True):
|
|
|
1410
1443
|
raise e
|
|
1411
1444
|
|
|
1412
1445
|
|
|
1446
|
+
async def graceful_exit(coder=None, exit_code=0):
|
|
1447
|
+
sys.settrace(None)
|
|
1448
|
+
|
|
1449
|
+
if coder:
|
|
1450
|
+
if hasattr(coder, "_autosave_future"):
|
|
1451
|
+
await coder._autosave_future
|
|
1452
|
+
|
|
1453
|
+
for server in coder.mcp_servers:
|
|
1454
|
+
try:
|
|
1455
|
+
await server.exit_stack.aclose()
|
|
1456
|
+
except Exception:
|
|
1457
|
+
pass
|
|
1458
|
+
|
|
1459
|
+
# Commenting since this can sometimes case hanging
|
|
1460
|
+
# await asyncio.sleep(0.5)
|
|
1461
|
+
return exit_code
|
|
1462
|
+
|
|
1463
|
+
|
|
1413
1464
|
if __name__ == "__main__":
|
|
1414
1465
|
status = main()
|
|
1415
1466
|
sys.exit(status)
|
aider/models.py
CHANGED
|
@@ -12,15 +12,15 @@ from dataclasses import dataclass, fields
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import Optional, Union
|
|
14
14
|
|
|
15
|
-
import json5
|
|
16
15
|
import yaml
|
|
17
16
|
from PIL import Image
|
|
18
17
|
|
|
19
18
|
from aider import __version__
|
|
20
19
|
from aider.dump import dump # noqa: F401
|
|
20
|
+
from aider.helpers.requests import model_request_parser
|
|
21
21
|
from aider.llm import litellm
|
|
22
22
|
from aider.openrouter import OpenRouterModelManager
|
|
23
|
-
from aider.sendchat import
|
|
23
|
+
from aider.sendchat import sanity_check_messages
|
|
24
24
|
from aider.utils import check_pip_install_extra
|
|
25
25
|
|
|
26
26
|
RETRY_TIMEOUT = 60
|
|
@@ -98,7 +98,8 @@ MODEL_ALIASES = {
|
|
|
98
98
|
"quasar": "openrouter/openrouter/quasar-alpha",
|
|
99
99
|
"r1": "deepseek/deepseek-reasoner",
|
|
100
100
|
"gemini-2.5-pro": "gemini/gemini-2.5-pro",
|
|
101
|
-
"gemini": "gemini/gemini-
|
|
101
|
+
"gemini-3-pro-preview": "gemini/gemini-3-pro-preview",
|
|
102
|
+
"gemini": "gemini/gemini-3-pro-preview",
|
|
102
103
|
"gemini-exp": "gemini/gemini-2.5-pro-exp-03-25",
|
|
103
104
|
"grok3": "xai/grok-3-beta",
|
|
104
105
|
"optimus": "openrouter/openrouter/optimus-alpha",
|
|
@@ -438,7 +439,7 @@ class Model(ModelSettings):
|
|
|
438
439
|
return # <--
|
|
439
440
|
|
|
440
441
|
last_segment = model.split("/")[-1]
|
|
441
|
-
if last_segment in ("gpt-5", "gpt-5-2025-08-07"):
|
|
442
|
+
if last_segment in ("gpt-5", "gpt-5-2025-08-07") or "gpt-5.1" in model:
|
|
442
443
|
self.use_temperature = False
|
|
443
444
|
self.edit_format = "diff"
|
|
444
445
|
if "reasoning_effort" not in self.accepts_settings:
|
|
@@ -909,7 +910,7 @@ class Model(ModelSettings):
|
|
|
909
910
|
if os.environ.get("AIDER_SANITY_CHECK_TURNS"):
|
|
910
911
|
sanity_check_messages(messages)
|
|
911
912
|
|
|
912
|
-
messages =
|
|
913
|
+
messages = model_request_parser(self, messages)
|
|
913
914
|
|
|
914
915
|
if self.verbose:
|
|
915
916
|
for message in messages:
|
|
@@ -976,6 +977,14 @@ class Model(ModelSettings):
|
|
|
976
977
|
dump(kwargs)
|
|
977
978
|
kwargs["messages"] = messages
|
|
978
979
|
|
|
980
|
+
# Cache System Prompts When Possible
|
|
981
|
+
kwargs["cache_control_injection_points"] = [
|
|
982
|
+
{
|
|
983
|
+
"location": "message",
|
|
984
|
+
"role": "system",
|
|
985
|
+
},
|
|
986
|
+
]
|
|
987
|
+
|
|
979
988
|
# Are we using github copilot?
|
|
980
989
|
if "GITHUB_COPILOT_TOKEN" in os.environ or self.name.startswith("github_copilot/"):
|
|
981
990
|
if "extra_headers" not in kwargs:
|
|
@@ -1000,8 +1009,7 @@ class Model(ModelSettings):
|
|
|
1000
1009
|
from aider.exceptions import LiteLLMExceptions
|
|
1001
1010
|
|
|
1002
1011
|
litellm_ex = LiteLLMExceptions()
|
|
1003
|
-
|
|
1004
|
-
messages = ensure_alternating_roles(messages)
|
|
1012
|
+
messages = model_request_parser(self, messages)
|
|
1005
1013
|
retry_delay = 0.125
|
|
1006
1014
|
|
|
1007
1015
|
if self.verbose:
|
|
@@ -1094,7 +1102,7 @@ def register_litellm_models(model_fnames):
|
|
|
1094
1102
|
data = Path(model_fname).read_text()
|
|
1095
1103
|
if not data.strip():
|
|
1096
1104
|
continue
|
|
1097
|
-
model_def =
|
|
1105
|
+
model_def = json.loads(data)
|
|
1098
1106
|
if not model_def:
|
|
1099
1107
|
continue
|
|
1100
1108
|
|
|
@@ -78,6 +78,11 @@
|
|
|
78
78
|
;; first element
|
|
79
79
|
(list_lit . [(sym_lit) (package_lit)] @name.reference.call) @reference.call
|
|
80
80
|
|
|
81
|
+
(list_lit
|
|
82
|
+
. (sym_lit) @import_call
|
|
83
|
+
. (sym_lit) @name.reference.import
|
|
84
|
+
(#match? @import_call "^(require|load)$")) @reference.import
|
|
85
|
+
|
|
81
86
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
82
87
|
;;; classes
|
|
83
88
|
|
|
@@ -24,3 +24,9 @@
|
|
|
24
24
|
(namespace_declaration name: (identifier) @name.definition.module) @definition.module
|
|
25
25
|
|
|
26
26
|
(namespace_declaration name: (identifier) @name.definition.module) @module
|
|
27
|
+
|
|
28
|
+
(using_directive
|
|
29
|
+
(qualified_name) @name.reference.import) @reference.import
|
|
30
|
+
|
|
31
|
+
(using_directive
|
|
32
|
+
(identifier) @name.reference.import) @reference.import
|
|
@@ -40,3 +40,10 @@
|
|
|
40
40
|
(var_declaration (var_spec name: (identifier) @name.definition.variable))
|
|
41
41
|
|
|
42
42
|
(const_declaration (const_spec name: (identifier) @name.definition.constant))
|
|
43
|
+
|
|
44
|
+
(import_spec
|
|
45
|
+
path: [
|
|
46
|
+
(interpreted_string_literal)
|
|
47
|
+
(raw_string_literal)
|
|
48
|
+
] @name.reference.import) @reference.import
|
|
49
|
+
|
|
@@ -18,3 +18,9 @@
|
|
|
18
18
|
type: (type_identifier) @name.reference.class) @reference.class
|
|
19
19
|
|
|
20
20
|
(superclass (type_identifier) @name.reference.class) @reference.class
|
|
21
|
+
|
|
22
|
+
(import_declaration
|
|
23
|
+
(scoped_identifier) @name.reference.import) @reference.import
|
|
24
|
+
|
|
25
|
+
(import_declaration
|
|
26
|
+
(identifier) @name.reference.import) @reference.import
|
|
@@ -86,3 +86,11 @@
|
|
|
86
86
|
|
|
87
87
|
(new_expression
|
|
88
88
|
constructor: (_) @name.reference.class) @reference.class
|
|
89
|
+
|
|
90
|
+
(import_statement
|
|
91
|
+
source: (string (string_fragment) @name.reference.import)) @reference.import
|
|
92
|
+
|
|
93
|
+
(call_expression
|
|
94
|
+
function: (identifier) @import_func
|
|
95
|
+
arguments: (arguments (string (string_fragment) @name.reference.import))
|
|
96
|
+
(#eq? @import_func "require")) @reference.import
|
|
@@ -32,3 +32,8 @@
|
|
|
32
32
|
(method_index_expression
|
|
33
33
|
method: (identifier) @name.reference.method)
|
|
34
34
|
]) @reference.call
|
|
35
|
+
|
|
36
|
+
(function_call
|
|
37
|
+
name: (identifier) @import_func
|
|
38
|
+
arguments: (arguments (string (string_content) @name.reference.import))
|
|
39
|
+
(#eq? @import_func "require")) @reference.import
|
|
@@ -12,3 +12,13 @@
|
|
|
12
12
|
(attribute
|
|
13
13
|
attribute: (identifier) @name.reference.call)
|
|
14
14
|
]) @reference.call
|
|
15
|
+
|
|
16
|
+
(import_statement
|
|
17
|
+
name: (dotted_name) @name.reference.import) @reference.import
|
|
18
|
+
|
|
19
|
+
(import_statement
|
|
20
|
+
name: (aliased_import
|
|
21
|
+
name: (dotted_name) @name.reference.import)) @reference.import
|
|
22
|
+
|
|
23
|
+
(import_from_statement
|
|
24
|
+
module_name: (dotted_name) @name.reference.import) @reference.import
|
|
@@ -62,3 +62,8 @@
|
|
|
62
62
|
(#is-not? local)
|
|
63
63
|
(#not-match? @name.reference.call "^(lambda|load|require|require_relative|__FILE__|__LINE__)$")
|
|
64
64
|
)
|
|
65
|
+
|
|
66
|
+
(call
|
|
67
|
+
method: (identifier) @import_method
|
|
68
|
+
arguments: (argument_list (string (string_content) @name.reference.import))
|
|
69
|
+
(#match? @import_method "^(require|require_relative|load)$")) @reference.import
|
|
@@ -48,4 +48,7 @@
|
|
|
48
48
|
) @definition.property
|
|
49
49
|
|
|
50
50
|
(function_declaration
|
|
51
|
-
|
|
51
|
+
name: (simple_identifier) @name.definition.function) @definition.function
|
|
52
|
+
|
|
53
|
+
(import_declaration
|
|
54
|
+
"import" @name.reference.import) @reference.import
|
|
@@ -44,3 +44,9 @@
|
|
|
44
44
|
(namespace_declaration
|
|
45
45
|
name: (identifier) @name.definition.module
|
|
46
46
|
) @definition.module
|
|
47
|
+
|
|
48
|
+
(using_directive
|
|
49
|
+
(qualified_name) @name.reference.import) @reference.import
|
|
50
|
+
|
|
51
|
+
(using_directive
|
|
52
|
+
(identifier) @name.reference.import) @reference.import
|