From 52d04430db7498989272182349044e12ba338630 Mon Sep 17 00:00:00 2001 From: contributor Date: Mon, 23 Jun 2025 12:45:45 +0300 Subject: [PATCH 1/5] feat: Auto-create parent directories for chat history files This prevents aider startup errors like: ``` Warning: Unable to write to chat history file .chat/.aider.chat.history.md. [Errno 2] No such file or directory: '.chat/.aider.chat.history.md' ``` --- aider/io.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aider/io.py b/aider/io.py index f8cf78cd3..f0000e965 100644 --- a/aider/io.py +++ b/aider/io.py @@ -731,6 +731,7 @@ class InputOutput: if not self.input_history_file: return try: + Path(self.input_history_file).parent.mkdir(parents=True, exist_ok=True) 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: @@ -1116,6 +1117,7 @@ class InputOutput: text += "\n" if self.chat_history_file is not None: try: + self.chat_history_file.parent.mkdir(parents=True, exist_ok=True) with self.chat_history_file.open("a", encoding=self.encoding, errors="ignore") as f: f.write(text) except (PermissionError, OSError) as err: From 05ca9e5c240f9ae6487953c635f0b078e1037601 Mon Sep 17 00:00:00 2001 From: therealmarv <1050582+therealmarv@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:07:01 +0200 Subject: [PATCH 2/5] add Gemini 2.5 non-preview Vertex models --- aider/resources/model-metadata.json | 55 +++++++++++++++++++++++++++++ aider/resources/model-settings.yml | 14 ++++++++ 2 files changed, 69 insertions(+) diff --git a/aider/resources/model-metadata.json b/aider/resources/model-metadata.json index b406ce4ff..f8b443439 100644 --- a/aider/resources/model-metadata.json +++ b/aider/resources/model-metadata.json @@ -276,6 +276,61 @@ "supports_tool_choice": true, "source": "https://cloud.google.com/vertex-ai/generative-ai/pricing" }, + "vertex_ai/gemini-2.5-pro": { + "max_tokens": 65536, + "max_input_tokens": 1048576, + "max_output_tokens": 65536, + "max_images_per_prompt": 3000, + "max_videos_per_prompt": 10, + "max_video_length": 1, + "max_audio_length_hours": 8.4, + "max_audio_per_prompt": 1, + "max_pdf_size_mb": 20, + "input_cost_per_token": 0.00000125, + "input_cost_per_token_above_200k_tokens": 0.0000025, + "output_cost_per_token": 0.00001, + "output_cost_per_token_above_200k_tokens": 0.000015, + "litellm_provider": "vertex_ai-language-models", + "mode": "chat", + "rpm": 2000, + "tpm": 8000000, + "supports_system_messages": true, + "supports_function_calling": true, + "supports_vision": true, + "supports_response_schema": true, + "supports_audio_output": false, + "supports_tool_choice": true, + "supported_modalities": ["text", "image", "audio", "video"], + "supported_output_modalities": ["text"], + "source": "https://cloud.google.com/vertex-ai/generative-ai/pricing" + }, + "vertex_ai/gemini-2.5-flash": { + "max_tokens": 65536, + "max_input_tokens": 1048576, + "max_output_tokens": 65536, + "max_images_per_prompt": 3000, + "max_videos_per_prompt": 10, + "max_video_length": 1, + "max_audio_length_hours": 8.4, + "max_audio_per_prompt": 1, + "max_pdf_size_mb": 20, + "input_cost_per_token": 0.0000003, + "input_cost_per_audio_token": 0.000001, + "output_cost_per_token": 0.0000025, + "litellm_provider": "vertex_ai-language-models", + "mode": "chat", + "rpm": 10000, + "tpm": 8000000, + "supports_system_messages": true, + "supports_function_calling": true, + "supports_vision": true, + "supports_response_schema": true, + "supports_audio_output": false, + "supports_tool_choice": true, + "supported_modalities": ["text", "image", "audio", "video"], + "supported_output_modalities": ["text"], + "source": "https://cloud.google.com/vertex-ai/generative-ai/pricing" + }, "openrouter/google/gemini-2.5-pro-preview-03-25": { "max_tokens": 8192, "max_input_tokens": 1048576, diff --git a/aider/resources/model-settings.yml b/aider/resources/model-settings.yml index 01ad14aef..3c91e3663 100644 --- a/aider/resources/model-settings.yml +++ b/aider/resources/model-settings.yml @@ -1474,6 +1474,20 @@ editor_model_name: vertex_ai/gemini-2.5-flash-preview-04-17 accepts_settings: ["thinking_tokens"] +- name: vertex_ai/gemini-2.5-pro + edit_format: diff-fenced + use_repo_map: true + weak_model_name: vertex_ai/gemini-2.5-flash + overeager: true + editor_model_name: vertex_ai/gemini-2.5-flash + accepts_settings: ["thinking_tokens"] + +- name: vertex_ai/gemini-2.5-flash + overeager: true + edit_format: diff-fenced + use_repo_map: true + accepts_settings: ["thinking_tokens"] + - name: openrouter/google/gemini-2.5-pro-preview-05-06 overeager: true edit_format: diff-fenced From c4b9f14b906b19bc961bd6b6730c7328fa3d0e9e Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Tue, 24 Jun 2025 20:46:40 +0200 Subject: [PATCH 3/5] fix: Resolve literal paths correctly in /read-only command --- aider/commands.py | 21 ++++++++++++++++----- tests/basic/test_commands.py | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/aider/commands.py b/aider/commands.py index e21f29d98..9bac9bab1 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -1316,12 +1316,23 @@ class Commands: # First collect all expanded paths for pattern in filenames: expanded_pattern = expanduser(pattern) - if os.path.isabs(expanded_pattern): - # For absolute paths, glob it - matches = list(glob.glob(expanded_pattern)) + path_obj = Path(expanded_pattern) + is_abs = path_obj.is_absolute() + if not is_abs: + path_obj = Path(self.coder.root) / path_obj + + matches = [] + # Check for literal path existence first + if path_obj.exists(): + matches = [path_obj] else: - # For relative paths and globs, use glob from the root directory - matches = list(Path(self.coder.root).glob(expanded_pattern)) + # If literal path doesn't exist, try globbing + if is_abs: + # For absolute paths, glob it + matches = [Path(p) for p in glob.glob(expanded_pattern)] + else: + # For relative paths and globs, use glob from the root directory + matches = list(Path(self.coder.root).glob(expanded_pattern)) if not matches: self.io.tool_error(f"No matches found for: {pattern}") diff --git a/tests/basic/test_commands.py b/tests/basic/test_commands.py index d187ee521..47b8832dc 100644 --- a/tests/basic/test_commands.py +++ b/tests/basic/test_commands.py @@ -1621,6 +1621,33 @@ class TestCommands(TestCase): # Clean up: remove the test file from the home directory test_file.unlink() + # pytest tests/basic/test_commands.py -k test_cmd_read_only_with_square_brackets + def test_cmd_read_only_with_square_brackets(self): + with GitTemporaryDirectory() as repo_dir: + io = InputOutput(pretty=False, fancy_input=False, yes=False) + coder = Coder.create(self.GPT35, None, io) + commands = Commands(io, coder) + + # Create test layout + test_dir = Path(repo_dir) / "[id]" + test_dir.mkdir() + test_file = Path(repo_dir) / "[id]" / "page.tsx" + test_file.write_text("Test file") + + # Test the /read-only command + commands.cmd_read_only("[id]/page.tsx") + + # Check if test file was added to abs_read_only_fnames + self.assertTrue( + any(os.path.samefile(str(test_file), fname) for fname in coder.abs_read_only_fnames) + ) + + # Test dropping all read-only files + commands.cmd_drop("[id]/page.tsx") + + # Check if all files were removed from abs_read_only_fnames + self.assertEqual(len(coder.abs_read_only_fnames), 0) + def test_cmd_diff(self): with GitTemporaryDirectory() as repo_dir: repo = git.Repo(repo_dir) From f695e71398e4786f5eca4b57e4b9ce4f9455a8ce Mon Sep 17 00:00:00 2001 From: contributor Date: Wed, 25 Jun 2025 13:34:14 +0300 Subject: [PATCH 4/5] feat: better place to create history file dirs (InputOutput ctr) this decreases number of IO operations --- aider/io.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aider/io.py b/aider/io.py index f0000e965..46621cfce 100644 --- a/aider/io.py +++ b/aider/io.py @@ -308,9 +308,11 @@ class InputOutput: self.yes = yes self.input_history_file = input_history_file + Path(self.input_history_file).parent.mkdir(parents=True, exist_ok=True) self.llm_history_file = llm_history_file if chat_history_file is not None: self.chat_history_file = Path(chat_history_file) + self.chat_history_file.parent.mkdir(parents=True, exist_ok=True) else: self.chat_history_file = None @@ -731,7 +733,6 @@ class InputOutput: if not self.input_history_file: return try: - Path(self.input_history_file).parent.mkdir(parents=True, exist_ok=True) 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: @@ -1117,7 +1118,6 @@ class InputOutput: text += "\n" if self.chat_history_file is not None: try: - self.chat_history_file.parent.mkdir(parents=True, exist_ok=True) with self.chat_history_file.open("a", encoding=self.encoding, errors="ignore") as f: f.write(text) except (PermissionError, OSError) as err: From fb4d2f90c1748154ee7eb59eeb55a59bb06a624d Mon Sep 17 00:00:00 2001 From: contributor Date: Wed, 25 Jun 2025 15:58:00 +0300 Subject: [PATCH 5/5] fix: check for input_history_file none --- aider/io.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aider/io.py b/aider/io.py index 46621cfce..5dde5ca7f 100644 --- a/aider/io.py +++ b/aider/io.py @@ -307,8 +307,9 @@ class InputOutput: self.yes = yes + if input_history_file is not None: + Path(input_history_file).mkdir(parents=True, exist_ok=True) self.input_history_file = input_history_file - Path(self.input_history_file).parent.mkdir(parents=True, exist_ok=True) self.llm_history_file = llm_history_file if chat_history_file is not None: self.chat_history_file = Path(chat_history_file)