Skip to content

Commit e7666de

Browse files
Refactor browser_use MIME type detection
Replace if-elif chain with dictionary-based lookup for cleaner, more maintainable code. Extract detection logic into reusable detect_image_mime_type() helper function. Add comprehensive test coverage for JPEG, PNG, GIF, WebP, and unknown formats. Co-authored-by: openhands <[email protected]>
1 parent f783fcf commit e7666de

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

openhands-tools/openhands/tools/browser_use/definition.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,29 @@
2424
# Maximum output size for browser observations
2525
MAX_BROWSER_OUTPUT_SIZE = 50000
2626

27+
# Mapping of base64 prefixes to MIME types for image detection
28+
BASE64_IMAGE_PREFIXES = {
29+
"/9j/": "image/jpeg",
30+
"iVBORw0KGgo": "image/png",
31+
"R0lGODlh": "image/gif",
32+
"UklGR": "image/webp",
33+
}
34+
35+
36+
def detect_image_mime_type(base64_data: str) -> str:
37+
"""Detect MIME type from base64-encoded image data.
38+
39+
Args:
40+
base64_data: Base64-encoded image data
41+
42+
Returns:
43+
Detected MIME type, defaults to "image/png" if not detected
44+
"""
45+
for prefix, mime_type in BASE64_IMAGE_PREFIXES.items():
46+
if base64_data.startswith(prefix):
47+
return mime_type
48+
return "image/png"
49+
2750

2851
class BrowserObservation(Observation):
2952
"""Base observation for browser operations."""
@@ -48,15 +71,7 @@ def to_llm_content(self) -> Sequence[TextContent | ImageContent]:
4871
)
4972

5073
if self.screenshot_data:
51-
mime_type = "image/png"
52-
if self.screenshot_data.startswith("/9j/"):
53-
mime_type = "image/jpeg"
54-
elif self.screenshot_data.startswith("iVBORw0KGgo"):
55-
mime_type = "image/png"
56-
elif self.screenshot_data.startswith("R0lGODlh"):
57-
mime_type = "image/gif"
58-
elif self.screenshot_data.startswith("UklGR"):
59-
mime_type = "image/webp"
74+
mime_type = detect_image_mime_type(self.screenshot_data)
6075
# Convert base64 to data URL format for ImageContent
6176
data_url = f"data:{mime_type};base64,{self.screenshot_data}"
6277
llm_content.append(ImageContent(image_urls=[data_url]))

tests/tools/browser_use/test_browser_observation.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,41 @@ def test_browser_observation_empty_screenshot_handling():
112112
observation = BrowserObservation.from_text(text="Test", screenshot_data=None)
113113
agent_obs = observation.to_llm_content
114114
assert len(agent_obs) == 1 # Only text content, no image
115+
116+
117+
def test_browser_observation_mime_type_detection():
118+
"""Test MIME type detection for different image formats."""
119+
test_cases = [
120+
(
121+
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", # noqa: E501
122+
"image/png",
123+
),
124+
(
125+
"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwA/", # noqa: E501
126+
"image/jpeg",
127+
),
128+
(
129+
"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
130+
"image/gif",
131+
),
132+
(
133+
"UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAQAcJaQAA3AA/v3AgAA=",
134+
"image/webp",
135+
),
136+
(
137+
"AAAABBBBCCCC", # Unknown format
138+
"image/png", # Falls back to PNG
139+
),
140+
]
141+
142+
for screenshot_data, expected_mime_type in test_cases:
143+
observation = BrowserObservation.from_text(
144+
text="Test", screenshot_data=screenshot_data
145+
)
146+
agent_obs = observation.to_llm_content
147+
148+
assert len(agent_obs) == 2
149+
assert isinstance(agent_obs[1], ImageContent)
150+
assert (
151+
agent_obs[1].image_urls[0].startswith(f"data:{expected_mime_type};base64,")
152+
)

0 commit comments

Comments
 (0)