Skip to content

⚡️ Speed up method Message._string_serializer by 7% #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

codeflash-ai[bot]
Copy link

@codeflash-ai codeflash-ai bot commented Mar 31, 2025

📄 7% (0.07x) speedup for Message._string_serializer in openhands/core/message.py

⏱️ Runtime : 14.3 microseconds 13.3 microseconds (best of 78 runs)

📝 Explanation and details

Changes made:

  1. Early Check for _add_tool_call_keys: By checking if self.tool_calls or self.tool_call_id is present before calling _add_tool_call_keys, we can bypass unnecessary computations when there are no tool calls to process.

  2. Separate and Clarify Appending to tool_calls_list: Changed from using a list comprehension to a loop. This simplifies readability and maintains efficiency. This still keeps preprocessing and dictionary construction focused and clear. Directly modifying the message_dict in case of tool entries ensures we're not repeatedly finalizing an unnecessary dictionary structure.

  3. Removing the Return in _add_tool_call_keys: By handling message_dict directly as it's a mutable object, we ensure that performance isn't degraded by unnecessary copying and that mutating inherently changes the dictionary in _string_serializer.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 14 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests Details
from typing import Literal

# imports
import pytest  # used for our unit tests
from openhands.core.message import Message
from pydantic import BaseModel


# Mocking the TextContent and ImageContent classes for testing
class TextContent:
    def __init__(self, text):
        self.text = text

class ImageContent:
    def __init__(self, image_data):
        self.image_data = image_data

# Mocking the ChatCompletionMessageToolCall class for testing
class Function:
    def __init__(self, name, arguments):
        self.name = name
        self.arguments = arguments

class ChatCompletionMessageToolCall:
    def __init__(self, id, function):
        self.id = id
        self.function = function

# unit tests




def test_empty_content():
    # Test with empty content list
    message = Message(role='tool', content=[])
    codeflash_output = message._string_serializer(); result = codeflash_output



def test_no_tool_calls():
    # Test with no tool calls
    message = Message(role='system', tool_calls=None, tool_call_id=None)
    codeflash_output = message._string_serializer(); result = codeflash_output



def test_tool_call_response():
    # Test with tool call response
    message = Message(role='assistant', tool_call_id="123", name="tool_name")
    codeflash_output = message._string_serializer(); result = codeflash_output







from typing import List, Literal, Union

# imports
import pytest  # used for our unit tests
# function to test
from litellm import ChatCompletionMessageToolCall
from openhands.core.message import Message
from pydantic import BaseModel, Field


class TextContent:
    def __init__(self, text: str):
        self.text = text

class ImageContent:
    def __init__(self, image_data: bytes):
        self.image_data = image_data

# unit tests



def test_empty_content():
    # Test with empty content
    message = Message(role='tool', content=[])
    codeflash_output = message._string_serializer(); result = codeflash_output



def test_no_tool_calls():
    # Test with no tool calls
    message = Message(role='system', tool_calls=None)
    codeflash_output = message._string_serializer(); result = codeflash_output



def test_tool_call_response():
    # Test with tool call response
    message = Message(role='tool', tool_call_id='123', name='tool_name')
    codeflash_output = message._string_serializer(); result = codeflash_output

def test_tool_call_without_name():
    # Test tool call response without name should raise assertion
    with pytest.raises(AssertionError):
        message = Message(role='tool', tool_call_id='123')
        message._string_serializer()

To edit these changes git checkout codeflash/optimize-Message._string_serializer-m8wsiuwl and push.

Codeflash

**Changes made:**
1. **Early Check for `_add_tool_call_keys`:** By checking if `self.tool_calls` or `self.tool_call_id` is present before calling `_add_tool_call_keys`, we can bypass unnecessary computations when there are no tool calls to process.

2. **Separate and Clarify Appending to `tool_calls_list`:** Changed from using a list comprehension to a loop. This simplifies readability and maintains efficiency. This still keeps preprocessing and dictionary construction focused and clear. Directly modifying the `message_dict` in case of tool entries ensures we're not repeatedly finalizing an unnecessary dictionary structure.

3. **Removing the Return in `_add_tool_call_keys`:** By handling `message_dict` directly as it's a mutable object, we ensure that performance isn't degraded by unnecessary copying and that mutating inherently changes the dictionary in `_string_serializer`.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Mar 31, 2025
@codeflash-ai codeflash-ai bot requested a review from dasarchan March 31, 2025 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚡️ codeflash Optimization PR opened by Codeflash AI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0 participants