diff --git a/aider/__init__.py b/aider/__init__.py index 04baaec73cc..500230c5098 100644 --- a/aider/__init__.py +++ b/aider/__init__.py @@ -1,6 +1,6 @@ from packaging import version -__version__ = "0.88.8.dev" +__version__ = "0.88.9.dev" safe_version = __version__ try: diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 7de98e32c29..7fabf2929d2 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -2743,6 +2743,8 @@ async def send(self, messages, model=None, functions=None, tools=None): format_content("ASSISTANT", self.partial_response_content), ) + self.preprocess_response() + if self.partial_response_content: self.io.ai_output(self.partial_response_content) elif self.partial_response_function_call: @@ -2986,6 +2988,21 @@ def render_incremental_response(self, final): # Just return the current content - the streaming logic will handle incremental updates return self.get_multi_response_content_in_progress() + def preprocess_response(self): + if len(self.partial_response_tool_calls): + tool_list = [] + tool_id_set = set() + + for tool_call_dict in self.partial_response_tool_calls: + # LLM APIs sometimes return duplicates and that's annoying part 2 + if tool_call_dict.get("id") in tool_id_set: + continue + + tool_id_set.add(tool_call_dict.get("id")) + tool_list.append(tool_call_dict) + + self.partial_response_tool_calls = tool_list + def remove_reasoning_content(self): """Remove reasoning content from the model's response.""" diff --git a/aider/sendchat.py b/aider/sendchat.py index 6f8b2ba5d04..7060c28b21e 100644 --- a/aider/sendchat.py +++ b/aider/sendchat.py @@ -179,7 +179,9 @@ def ensure_alternating_roles(messages): # Add missing tool responses as empty for tool_id in expected_ids: - tool_sequence.append({"role": "tool", "tool_call_id": tool_id, "content": ""}) + tool_sequence.append( + {"role": "tool", "tool_call_id": tool_id, "content": "(empty response)"} + ) # Add the complete tool sequence to result for tool_msg in tool_sequence: @@ -194,7 +196,16 @@ def ensure_alternating_roles(messages): if role == prev_role: # Insert empty message of opposite role opposite_role = "user" if role == "assistant" else "assistant" - result.append({"role": opposite_role, "content": ""}) + result.append( + { + "role": opposite_role, + "content": ( + "(empty response)" + if opposite_role == "assistant" + else "(empty request)" + ), + } + ) prev_role = opposite_role result.append(msg) @@ -221,8 +232,8 @@ def ensure_alternating_roles(messages): current_role in ("user", "assistant") and last_role in ("user", "assistant") and current_role == last_role - and msg.get("content") == "" - and last_msg.get("content") == "" + and msg.get("content") in ["", "(empty response)", "(empty request)"] + and last_msg.get("content") in ["", "(empty response)", "(empty request)"] ): continue diff --git a/tests/basic/test_sendchat.py b/tests/basic/test_sendchat.py index 153ab2f421f..69cc79f350c 100644 --- a/tests/basic/test_sendchat.py +++ b/tests/basic/test_sendchat.py @@ -133,7 +133,7 @@ def test_ensure_alternating_roles_consecutive_user(self): ] expected = [ {"role": "user", "content": "Hello"}, - {"role": "assistant", "content": ""}, + {"role": "assistant", "content": "(empty response)"}, {"role": "user", "content": "Are you there?"}, ] result = ensure_alternating_roles(messages) @@ -148,7 +148,7 @@ def test_ensure_alternating_roles_consecutive_assistant(self): ] expected = [ {"role": "assistant", "content": "Hi there"}, - {"role": "user", "content": ""}, + {"role": "user", "content": "(empty request)"}, {"role": "assistant", "content": "How can I help?"}, ] result = ensure_alternating_roles(messages) @@ -166,10 +166,10 @@ def test_ensure_alternating_roles_mixed_sequence(self): ] expected = [ {"role": "user", "content": "Hello"}, - {"role": "assistant", "content": ""}, + {"role": "assistant", "content": "(empty response)"}, {"role": "user", "content": "Are you there?"}, {"role": "assistant", "content": "Yes"}, - {"role": "user", "content": ""}, + {"role": "user", "content": "(empty request)"}, {"role": "assistant", "content": "How can I help?"}, {"role": "user", "content": "Write code"}, ]