From 45e3f6819c2a3fb6b8bc235b345846b15667a563 Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Wed, 19 Nov 2025 11:20:40 -0500 Subject: [PATCH 1/5] Bump Version --- aider/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/__init__.py b/aider/__init__.py index 0a53f1786e3..e7136a82fda 100644 --- a/aider/__init__.py +++ b/aider/__init__.py @@ -1,6 +1,6 @@ from packaging import version -__version__ = "0.88.21.dev" +__version__ = "0.88.22.dev" safe_version = __version__ try: From 12fa6e9325c23c6a5e6ea83f8f1e677445f78da0 Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Wed, 19 Nov 2025 11:21:21 -0500 Subject: [PATCH 2/5] Make sure function name actually exists for tool calls --- aider/coders/base_coder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 22d1b74b9fb..5675e2fc5f6 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -2308,7 +2308,7 @@ def _print_tool_call_info(self, server_tool_calls): # Parse and format arguments as headers with values if tool_call.function.arguments: # Only do JSON unwrapping for tools containing "replace" in their name - if ( + if tool_call.get("function", {}).get("name") is not None and ( "replace" in tool_call.function.name.lower() or "insert" in tool_call.function.name.lower() or "update" in tool_call.function.name.lower() From cb836b3dc2ac859cf1b12c9161de899e4fd5107b Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Wed, 19 Nov 2025 12:03:19 -0500 Subject: [PATCH 3/5] Update deepseek costs and token usage --- aider/resources/model-metadata.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/aider/resources/model-metadata.json b/aider/resources/model-metadata.json index 4a714d371e6..2f489eeead1 100644 --- a/aider/resources/model-metadata.json +++ b/aider/resources/model-metadata.json @@ -6523,14 +6523,14 @@ "supports_vision": true }, "deepseek-chat": { - "cache_read_input_token_cost": 6e-08, - "input_cost_per_token": 6e-07, + "cache_read_input_token_cost": 3e-08, + "input_cost_per_token": 3e-07, "litellm_provider": "deepseek", - "max_input_tokens": 131072, + "max_input_tokens": 128000, "max_output_tokens": 8192, - "max_tokens": 131072, + "max_tokens": 128000, "mode": "chat", - "output_cost_per_token": 1.7e-06, + "output_cost_per_token": 5e-07, "source": "https://api-docs.deepseek.com/quick_start/pricing", "supported_endpoints": [ "/v1/chat/completions" @@ -6544,14 +6544,14 @@ "supports_tool_choice": true }, "deepseek-reasoner": { - "cache_read_input_token_cost": 6e-08, - "input_cost_per_token": 6e-07, + "cache_read_input_token_cost": 3e-08, + "input_cost_per_token": 3e-07, "litellm_provider": "deepseek", - "max_input_tokens": 131072, + "max_input_tokens": 128000, "max_output_tokens": 65536, - "max_tokens": 131072, + "max_tokens": 128000, "mode": "chat", - "output_cost_per_token": 1.7e-06, + "output_cost_per_token": 5e-07, "source": "https://api-docs.deepseek.com/quick_start/pricing", "supported_endpoints": [ "/v1/chat/completions" From 32b29d64d6b27fc1919a710292e90a214a410859 Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Wed, 19 Nov 2025 12:09:11 -0500 Subject: [PATCH 4/5] Sync deepseek settings with provider alias --- aider/resources/model-metadata.json | 46 ++++++++++++++++++----------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/aider/resources/model-metadata.json b/aider/resources/model-metadata.json index 2f489eeead1..2a8c960e45a 100644 --- a/aider/resources/model-metadata.json +++ b/aider/resources/model-metadata.json @@ -8467,19 +8467,24 @@ "supports_tool_choice": true }, "deepseek/deepseek-chat": { - "cache_creation_input_token_cost": 0.0, - "cache_read_input_token_cost": 7e-08, - "input_cost_per_token": 2.7e-07, - "input_cost_per_token_cache_hit": 7e-08, + "cache_read_input_token_cost": 3e-08, + "input_cost_per_token": 3e-07, "litellm_provider": "deepseek", - "max_input_tokens": 65536, + "max_input_tokens": 128000, "max_output_tokens": 8192, - "max_tokens": 8192, + "max_tokens": 128000, "mode": "chat", - "output_cost_per_token": 1.1e-06, - "supports_assistant_prefill": true, + "output_cost_per_token": 5e-07, + "source": "https://api-docs.deepseek.com/quick_start/pricing", + "supported_endpoints": [ + "/v1/chat/completions" + ], "supports_function_calling": true, + "supports_native_streaming": true, + "supports_parallel_function_calling": true, "supports_prompt_caching": true, + "supports_response_schema": true, + "supports_system_messages": true, "supports_tool_choice": true }, "deepseek/deepseek-coder": { @@ -8512,19 +8517,26 @@ "supports_tool_choice": true }, "deepseek/deepseek-reasoner": { - "input_cost_per_token": 5.5e-07, - "input_cost_per_token_cache_hit": 1.4e-07, + "cache_read_input_token_cost": 3e-08, + "input_cost_per_token": 3e-07, "litellm_provider": "deepseek", - "max_input_tokens": 65536, - "max_output_tokens": 8192, - "max_tokens": 8192, + "max_input_tokens": 128000, + "max_output_tokens": 65536, + "max_tokens": 128000, "mode": "chat", - "output_cost_per_token": 2.19e-06, - "supports_assistant_prefill": true, - "supports_function_calling": true, + "output_cost_per_token": 5e-07, + "source": "https://api-docs.deepseek.com/quick_start/pricing", + "supported_endpoints": [ + "/v1/chat/completions" + ], + "supports_function_calling": false, + "supports_native_streaming": true, + "supports_parallel_function_calling": false, "supports_prompt_caching": true, "supports_reasoning": true, - "supports_tool_choice": true + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": false }, "deepseek/deepseek-v3": { "cache_creation_input_token_cost": 0.0, From d7b6eac10d9833a549dabcfc5fc04a95563173fa Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Wed, 19 Nov 2025 13:01:06 -0500 Subject: [PATCH 5/5] Address Inconsistent Tool Naming From Model Providers: - Gemini Uses Parallel tool calls so needs to use the chunk id directly - Deepseek uses numeric index positions after a single preamble with the tool id - Claude uses numeric index positions but it is 1 and not 0 based - So basically, use chunks if present, but because models generate sequentially, as long as there is a preamble, a tool call with an index and no id can be assumed to be a part of the prior tool call part --- aider/coders/base_coder.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 5675e2fc5f6..7b8b0f4d220 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -2926,6 +2926,7 @@ def show_send_output(self, completion): async def show_send_output_stream(self, completion): received_content = False id_index_dict = dict() + self._last_known_tool_index = 0 async for chunk in completion: # Check if confirmation is in progress and wait if needed @@ -2959,14 +2960,13 @@ async def show_send_output_stream(self, completion): len(self.partial_response_tool_calls) - 1 ) elif tool_call_chunk.id is None: - if len(self.partial_response_tool_calls) <= index: - self.partial_response_tool_calls.extend( - [{}] * (index - len(self.partial_response_tool_calls) + 1) - ) + index = self._last_known_tool_index if tool_call_chunk.id is not None: index = id_index_dict[tool_call_chunk.id] + self._last_known_tool_index = index + if tool_call_chunk.id: self.partial_response_tool_calls[index]["id"] = tool_call_chunk.id if tool_call_chunk.type: