Compare commits

...

10 Commits

Author SHA1 Message Date
Engel Nyst
9f3b2e70a0 Update openhands/memory/conversation_memory.py 2025-09-23 22:18:34 +02:00
Engel Nyst
dea4130837 Clean up blank lines in test_conversation_memory.py 2025-09-11 01:51:18 +02:00
enyst
b6c6d69c8c Remove unnecessary user finish action test
- Removed test_process_events_with_user_agent_finish_action as it was not part of the original PR
- Keep only the two original tests: empty and non-empty assistant finish actions
- Both original tests still pass and cover the intended fix
2025-09-10 23:44:25 +00:00
enyst
bf0d1933bd Clean up debug prints and fix user finish action test
- Removed all debug prints from conversation_memory.py and test file
- Fixed user finish action test expectation to match actual behavior
- All three test cases now pass: empty assistant, non-empty assistant, and user finish actions
- Core fix remains: empty assistant finish actions get 'Task completed.' default content
2025-09-10 23:42:54 +00:00
enyst
7a7b51a6f4 Add debug prints for troubleshooting test execution
- Added extensive debug prints throughout conversation_memory.py
- Debugging why fix code is present but not executing in pytest
- Fix is implemented in lines 303-308 for empty assistant finish actions
- Removed temporary test files
2025-09-10 23:39:28 +00:00
enyst
33f40b6a2b Resolve merge conflicts in test_conversation_memory.py
- Merged changes from main branch that added vision-related test assertions
- Preserved all three test functions for AgentFinishAction handling:
  - test_process_events_with_empty_agent_finish_action
  - test_process_events_with_non_empty_agent_finish_action
  - test_process_events_with_user_agent_finish_action
- Ensures comprehensive test coverage for the Mistral empty assistant message fix
2025-09-10 23:24:20 +00:00
enyst
5db9e51657 Fix failing unit test for empty AgentFinishAction
- Fixed module caching issue that was preventing the fix from being applied
- Ensured assistant messages with empty thoughts get 'Task completed.' as default content
- All AgentFinishAction-related tests now pass

Co-authored-by: openhands <openhands@all-hands.dev>
2025-09-07 07:21:29 +00:00
Engel Nyst
c5dca7d8e1 Merge branch 'main' into fix-mistral-empty-assistant-message 2025-08-25 10:44:21 +02:00
Engel Nyst
8f67420e48 Update openhands/memory/conversation_memory.py 2025-08-25 10:43:56 +02:00
enyst
e0e6131250 Fix MistralException for empty AgentFinishAction messages
- Add default content 'Task completed.' for empty assistant finish actions
- Only affects AgentFinishAction when role is 'assistant' and thought is empty
- Preserves original behavior for non-empty thoughts and user messages
- Add unit tests for empty and non-empty assistant finish actions

Fixes #8685

Co-authored-by: openhands <openhands@all-hands.dev>
2025-08-24 02:36:55 +00:00
2 changed files with 65 additions and 1 deletions

View File

@@ -293,10 +293,16 @@ class ConversationMemory:
action.tool_call_metadata = None
if role not in ('user', 'system', 'assistant', 'tool'):
raise ValueError(f'Invalid role: {role}')
# Ensure assistant messages have non-empty content (required by some LLM providers like Mistral)
if role == 'assistant' and not (action.thought and action.thought.strip()):
thought_text = 'Task completed.'
else:
thought_text = action.thought or ''
return [
Message(
role=role, # type: ignore[arg-type]
content=[TextContent(text=action.thought)],
content=[TextContent(text=thought_text)],
)
]
elif isinstance(action, MessageAction):

View File

@@ -1583,3 +1583,61 @@ def test_process_ipython_observation_with_vision_disabled(
assert isinstance(message.content[1], ImageContent)
# Check that NO explanatory text about filtered images was added when vision is disabled
assert 'invalid or empty image(s) were filtered' not in message.content[0].text
def test_process_events_with_empty_agent_finish_action(conversation_memory):
"""Test that AgentFinishAction with empty thought gets default content for assistant messages."""
# Create an AgentFinishAction with empty thought from assistant
empty_finish_action = AgentFinishAction(thought='')
empty_finish_action._source = EventSource.AGENT
initial_user_message = MessageAction(content='Initial user message')
initial_user_message._source = EventSource.USER
messages = conversation_memory.process_events(
condensed_history=[empty_finish_action],
initial_user_action=initial_user_message,
max_message_chars=None,
vision_is_active=False,
)
# Should have system message, initial user message, and assistant finish message
assert len(messages) == 3
# Check the assistant finish message
assistant_message = messages[2]
assert assistant_message.role == 'assistant'
assert len(assistant_message.content) == 1
assert isinstance(assistant_message.content[0], TextContent)
# Should have default content instead of empty string
assert assistant_message.content[0].text == 'Task completed.'
def test_process_events_with_non_empty_agent_finish_action(conversation_memory):
"""Test that AgentFinishAction with non-empty thought preserves original content."""
# Create an AgentFinishAction with non-empty thought from assistant
finish_action = AgentFinishAction(thought='I have completed the task successfully.')
finish_action._source = EventSource.AGENT
initial_user_message = MessageAction(content='Initial user message')
initial_user_message._source = EventSource.USER
messages = conversation_memory.process_events(
condensed_history=[finish_action],
initial_user_action=initial_user_message,
max_message_chars=None,
vision_is_active=False,
)
# Should have system message, initial user message, and assistant finish message
assert len(messages) == 3
# Check the assistant finish message
assistant_message = messages[2]
assert assistant_message.role == 'assistant'
assert len(assistant_message.content) == 1
assert isinstance(assistant_message.content[0], TextContent)
# Should preserve original content
assert (
assistant_message.content[0].text == 'I have completed the task successfully.'
)