Skip to content

Commit ae46372

Browse files
Reject string-subclass tool response text values
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent a8c40a1 commit ae46372

2 files changed

Lines changed: 17 additions & 7 deletions

File tree

hyperbrowser/tools/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def _to_param_dict(params: Mapping[str, Any]) -> Dict[str, Any]:
146146
if type(key) is str:
147147
try:
148148
normalized_key = key.strip()
149-
if not isinstance(normalized_key, str):
149+
if type(normalized_key) is not str:
150150
raise TypeError("normalized tool param key must be a string")
151151
is_empty_key = len(normalized_key) == 0
152152
except HyperbrowserError:
@@ -227,7 +227,7 @@ def _normalize_optional_text_field_value(
227227
) -> str:
228228
if field_value is None:
229229
return ""
230-
if isinstance(field_value, str):
230+
if type(field_value) is str:
231231
try:
232232
normalized_field_value = "".join(character for character in field_value)
233233
if type(normalized_field_value) is not str:
@@ -240,6 +240,8 @@ def _normalize_optional_text_field_value(
240240
error_message,
241241
original_error=exc,
242242
) from exc
243+
if isinstance(field_value, str):
244+
raise HyperbrowserError(error_message)
243245
if isinstance(field_value, (bytes, bytearray, memoryview)):
244246
try:
245247
normalized_field_value = memoryview(field_value).tobytes().decode("utf-8")

tests/test_tools_response_handling.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ def __iter__(self):
351351
) as exc_info:
352352
WebsiteScrapeTool.runnable(client, {"url": "https://example.com"})
353353

354-
assert exc_info.value.original_error is not None
354+
assert exc_info.value.original_error is None
355355

356356

357357
def test_scrape_tool_wraps_attributeerror_from_declared_markdown_property():
@@ -758,7 +758,9 @@ def __getitem__(self, key: str) -> object:
758758

759759
client = _SyncCrawlClient(_Response(data=[_BrokenContainsPage()]))
760760

761-
with pytest.raises(HyperbrowserError, match="custom page inspect failure") as exc_info:
761+
with pytest.raises(
762+
HyperbrowserError, match="custom page inspect failure"
763+
) as exc_info:
762764
WebsiteCrawlTool.runnable(client, {"url": "https://example.com"})
763765

764766
assert exc_info.value.original_error is None
@@ -782,7 +784,13 @@ def __iter__(self):
782784
raise RuntimeError("url iteration exploded")
783785

784786
client = _SyncCrawlClient(
785-
_Response(data=[SimpleNamespace(url=_BrokenUrlValue("https://example.com"), markdown="body")])
787+
_Response(
788+
data=[
789+
SimpleNamespace(
790+
url=_BrokenUrlValue("https://example.com"), markdown="body"
791+
)
792+
]
793+
)
786794
)
787795

788796
with pytest.raises(
@@ -791,7 +799,7 @@ def __iter__(self):
791799
) as exc_info:
792800
WebsiteCrawlTool.runnable(client, {"url": "https://example.com"})
793801

794-
assert exc_info.value.original_error is not None
802+
assert exc_info.value.original_error is None
795803

796804

797805
def test_crawl_tool_decodes_utf8_bytes_page_fields():
@@ -870,7 +878,7 @@ def __iter__(self):
870878
) as exc_info:
871879
BrowserUseTool.runnable(client, {"task": "search docs"})
872880

873-
assert exc_info.value.original_error is not None
881+
assert exc_info.value.original_error is None
874882

875883

876884
def test_browser_use_tool_wraps_attributeerror_from_declared_final_result_property():

0 commit comments

Comments
 (0)