test_message_serialization.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. from litellm import ChatCompletionMessageToolCall
  2. from openhands.core.message import ImageContent, Message, TextContent
  3. def test_message_with_vision_enabled():
  4. text_content1 = TextContent(text='This is a text message')
  5. image_content1 = ImageContent(
  6. image_urls=['http://example.com/image1.png', 'http://example.com/image2.png']
  7. )
  8. text_content2 = TextContent(text='This is another text message')
  9. image_content2 = ImageContent(
  10. image_urls=['http://example.com/image3.png', 'http://example.com/image4.png']
  11. )
  12. message: Message = Message(
  13. role='user',
  14. content=[text_content1, image_content1, text_content2, image_content2],
  15. vision_enabled=True,
  16. )
  17. serialized_message: dict = message.serialize_model()
  18. expected_serialized_message = {
  19. 'role': 'user',
  20. 'content': [
  21. {'type': 'text', 'text': 'This is a text message'},
  22. {
  23. 'type': 'image_url',
  24. 'image_url': {'url': 'http://example.com/image1.png'},
  25. },
  26. {
  27. 'type': 'image_url',
  28. 'image_url': {'url': 'http://example.com/image2.png'},
  29. },
  30. {'type': 'text', 'text': 'This is another text message'},
  31. {
  32. 'type': 'image_url',
  33. 'image_url': {'url': 'http://example.com/image3.png'},
  34. },
  35. {
  36. 'type': 'image_url',
  37. 'image_url': {'url': 'http://example.com/image4.png'},
  38. },
  39. ],
  40. }
  41. assert serialized_message == expected_serialized_message
  42. assert message.contains_image is True
  43. def test_message_with_only_text_content_and_vision_enabled():
  44. text_content1 = TextContent(text='This is a text message')
  45. text_content2 = TextContent(text='This is another text message')
  46. message: Message = Message(
  47. role='user', content=[text_content1, text_content2], vision_enabled=True
  48. )
  49. serialized_message: dict = message.serialize_model()
  50. expected_serialized_message = {
  51. 'role': 'user',
  52. 'content': [
  53. {'type': 'text', 'text': 'This is a text message'},
  54. {'type': 'text', 'text': 'This is another text message'},
  55. ],
  56. }
  57. assert serialized_message == expected_serialized_message
  58. assert message.contains_image is False
  59. def test_message_with_only_text_content_and_vision_disabled():
  60. text_content1 = TextContent(text='This is a text message')
  61. text_content2 = TextContent(text='This is another text message')
  62. message: Message = Message(
  63. role='user', content=[text_content1, text_content2], vision_enabled=False
  64. )
  65. serialized_message: dict = message.serialize_model()
  66. expected_serialized_message = {
  67. 'role': 'user',
  68. 'content': 'This is a text message\nThis is another text message',
  69. }
  70. assert serialized_message == expected_serialized_message
  71. assert message.contains_image is False
  72. def test_message_with_mixed_content_and_vision_disabled():
  73. # Create a message with both text and image content
  74. text_content1 = TextContent(text='This is a text message')
  75. image_content1 = ImageContent(
  76. image_urls=['http://example.com/image1.png', 'http://example.com/image2.png']
  77. )
  78. text_content2 = TextContent(text='This is another text message')
  79. image_content2 = ImageContent(
  80. image_urls=['http://example.com/image3.png', 'http://example.com/image4.png']
  81. )
  82. # Initialize Message with vision disabled
  83. message: Message = Message(
  84. role='user',
  85. content=[text_content1, image_content1, text_content2, image_content2],
  86. vision_enabled=False,
  87. )
  88. serialized_message: dict = message.serialize_model()
  89. # Expected serialization ignores images and concatenates text
  90. expected_serialized_message = {
  91. 'role': 'user',
  92. 'content': 'This is a text message\nThis is another text message',
  93. }
  94. # Assert serialized message matches expectation
  95. assert serialized_message == expected_serialized_message
  96. # Assert that images exist in the original message
  97. assert message.contains_image
  98. def test_message_tool_call_serialization():
  99. """Test that tool calls are properly serialized into dicts for token counting."""
  100. # Create a tool call
  101. tool_call = ChatCompletionMessageToolCall(
  102. id='call_123',
  103. type='function',
  104. function={'name': 'test_function', 'arguments': '{"arg1": "value1"}'},
  105. )
  106. # Create a message with the tool call
  107. message = Message(
  108. role='assistant',
  109. content=[TextContent(text='Test message')],
  110. tool_calls=[tool_call],
  111. )
  112. # Serialize the message
  113. serialized = message.model_dump()
  114. # Check that tool calls are properly serialized
  115. assert 'tool_calls' in serialized
  116. assert isinstance(serialized['tool_calls'], list)
  117. assert len(serialized['tool_calls']) == 1
  118. tool_call_dict = serialized['tool_calls'][0]
  119. assert isinstance(tool_call_dict, dict)
  120. assert tool_call_dict['id'] == 'call_123'
  121. assert tool_call_dict['type'] == 'function'
  122. assert tool_call_dict['function']['name'] == 'test_function'
  123. assert tool_call_dict['function']['arguments'] == '{"arg1": "value1"}'
  124. def test_message_tool_response_serialization():
  125. """Test that tool responses are properly serialized."""
  126. # Create a message with tool response
  127. message = Message(
  128. role='tool',
  129. content=[TextContent(text='Function result')],
  130. tool_call_id='call_123',
  131. name='test_function',
  132. )
  133. # Serialize the message
  134. serialized = message.model_dump()
  135. # Check that tool response fields are properly serialized
  136. assert 'tool_call_id' in serialized
  137. assert serialized['tool_call_id'] == 'call_123'
  138. assert 'name' in serialized
  139. assert serialized['name'] == 'test_function'