openhands-tools 1.7.1__py3-none-any.whl → 1.7.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,8 @@ from openhands.tools.browser_use.definition import (
9
9
  BrowserGetContentTool,
10
10
  BrowserGetStateAction,
11
11
  BrowserGetStateTool,
12
+ BrowserGetStorageAction,
13
+ BrowserGetStorageTool,
12
14
  BrowserGoBackAction,
13
15
  BrowserGoBackTool,
14
16
  BrowserListTabsAction,
@@ -18,6 +20,8 @@ from openhands.tools.browser_use.definition import (
18
20
  BrowserObservation,
19
21
  BrowserScrollAction,
20
22
  BrowserScrollTool,
23
+ BrowserSetStorageAction,
24
+ BrowserSetStorageTool,
21
25
  BrowserSwitchTabAction,
22
26
  BrowserSwitchTabTool,
23
27
  BrowserToolSet,
@@ -38,6 +42,8 @@ __all__ = [
38
42
  "BrowserListTabsTool",
39
43
  "BrowserSwitchTabTool",
40
44
  "BrowserCloseTabTool",
45
+ "BrowserGetStorageTool",
46
+ "BrowserSetStorageTool",
41
47
  # Actions
42
48
  "BrowserNavigateAction",
43
49
  "BrowserClickAction",
@@ -49,6 +55,8 @@ __all__ = [
49
55
  "BrowserListTabsAction",
50
56
  "BrowserSwitchTabAction",
51
57
  "BrowserCloseTabAction",
58
+ "BrowserGetStorageAction",
59
+ "BrowserSetStorageAction",
52
60
  # Observations
53
61
  "BrowserObservation",
54
62
  "BrowserToolSet",
@@ -1,6 +1,9 @@
1
1
  """Browser-use tool implementation for web automation."""
2
2
 
3
+ import base64
4
+ import hashlib
3
5
  from collections.abc import Sequence
6
+ from pathlib import Path
4
7
  from typing import TYPE_CHECKING, Literal, Self
5
8
 
6
9
  from pydantic import Field
@@ -57,6 +60,29 @@ class BrowserObservation(Observation):
57
60
  description="Directory where full output files are saved",
58
61
  )
59
62
 
63
+ def _save_screenshot(self, base64_data: str, save_dir: str) -> str | None:
64
+ try:
65
+ save_dir_path = Path(save_dir)
66
+ save_dir_path.mkdir(parents=True, exist_ok=True)
67
+
68
+ mime_type = detect_image_mime_type(base64_data)
69
+ ext = mime_type.split("/")[-1]
70
+ if ext == "jpeg":
71
+ ext = "jpg"
72
+
73
+ # Generate hash for filename
74
+ content_hash = hashlib.sha256(base64_data.encode("utf-8")).hexdigest()[:8]
75
+ filename = f"browser_screenshot_{content_hash}.{ext}"
76
+ file_path = save_dir_path / filename
77
+
78
+ if not file_path.exists():
79
+ image_data = base64.b64decode(base64_data)
80
+ file_path.write_bytes(image_data)
81
+
82
+ return str(file_path)
83
+ except Exception:
84
+ return None
85
+
60
86
  @property
61
87
  def to_llm_content(self) -> Sequence[TextContent | ImageContent]:
62
88
  llm_content: list[TextContent | ImageContent] = []
@@ -81,6 +107,17 @@ class BrowserObservation(Observation):
81
107
 
82
108
  if self.screenshot_data:
83
109
  mime_type = detect_image_mime_type(self.screenshot_data)
110
+
111
+ # Save screenshot if directory is available
112
+ if self.full_output_save_dir:
113
+ saved_path = self._save_screenshot(
114
+ self.screenshot_data, self.full_output_save_dir
115
+ )
116
+ if saved_path:
117
+ llm_content.append(
118
+ TextContent(text=f"Screenshot saved to: {saved_path}")
119
+ )
120
+
84
121
  # Convert base64 to data URL format for ImageContent
85
122
  data_url = f"data:{mime_type};base64,{self.screenshot_data}"
86
123
  llm_content.append(ImageContent(image_urls=[data_url]))
@@ -542,6 +579,95 @@ class BrowserCloseTabTool(ToolDefinition[BrowserCloseTabAction, BrowserObservati
542
579
  ]
543
580
 
544
581
 
582
+ # ============================================
583
+ # `browser_get_storage`
584
+ # ============================================
585
+ class BrowserGetStorageAction(BrowserAction):
586
+ """Schema for getting browser storage (cookies, local storage, session storage)."""
587
+
588
+ pass
589
+
590
+
591
+ BROWSER_GET_STORAGE_DESCRIPTION = """Get browser storage data including cookies,
592
+ local storage, and session storage.
593
+
594
+ This tool extracts all cookies and storage data from the current browser session.
595
+ Useful for debugging, session management, or extracting authentication tokens.
596
+ """
597
+
598
+
599
+ class BrowserGetStorageTool(
600
+ ToolDefinition[BrowserGetStorageAction, BrowserObservation]
601
+ ):
602
+ """Tool for getting browser storage."""
603
+
604
+ @classmethod
605
+ def create(cls, executor: "BrowserToolExecutor") -> Sequence[Self]:
606
+ return [
607
+ cls(
608
+ description=BROWSER_GET_STORAGE_DESCRIPTION,
609
+ action_type=BrowserGetStorageAction,
610
+ observation_type=BrowserObservation,
611
+ annotations=ToolAnnotations(
612
+ title="browser_get_storage",
613
+ readOnlyHint=True,
614
+ destructiveHint=False,
615
+ idempotentHint=True,
616
+ openWorldHint=False,
617
+ ),
618
+ executor=executor,
619
+ )
620
+ ]
621
+
622
+
623
+ # ============================================
624
+ # `browser_set_storage`
625
+ # ============================================
626
+ class BrowserSetStorageAction(BrowserAction):
627
+ """Schema for setting browser storage (cookies, local storage, session storage)."""
628
+
629
+ storage_state: dict = Field(
630
+ description="Storage state dictionary containing 'cookies' and 'origins' (from browser_get_storage)" # noqa: E501
631
+ )
632
+
633
+
634
+ BROWSER_SET_STORAGE_DESCRIPTION = """Set browser storage data including cookies,
635
+ local storage, and session storage.
636
+
637
+ This tool allows you to restore or set the browser's storage state. You can use the
638
+ output from browser_get_storage to restore a previous session.
639
+
640
+ Parameters:
641
+ - storage_state: A dictionary containing 'cookies' and 'origins'.
642
+ - cookies: List of cookie objects
643
+ - origins: List of origin objects containing 'localStorage' and 'sessionStorage'
644
+ """
645
+
646
+
647
+ class BrowserSetStorageTool(
648
+ ToolDefinition[BrowserSetStorageAction, BrowserObservation]
649
+ ):
650
+ """Tool for setting browser storage."""
651
+
652
+ @classmethod
653
+ def create(cls, executor: "BrowserToolExecutor") -> Sequence[Self]:
654
+ return [
655
+ cls(
656
+ description=BROWSER_SET_STORAGE_DESCRIPTION,
657
+ action_type=BrowserSetStorageAction,
658
+ observation_type=BrowserObservation,
659
+ annotations=ToolAnnotations(
660
+ title="browser_set_storage",
661
+ readOnlyHint=False,
662
+ destructiveHint=True,
663
+ idempotentHint=False,
664
+ openWorldHint=False,
665
+ ),
666
+ executor=executor,
667
+ )
668
+ ]
669
+
670
+
545
671
  class BrowserToolSet(ToolDefinition[BrowserAction, BrowserObservation]):
546
672
  """A set of all browser tools.
547
673
 
@@ -593,6 +719,8 @@ class BrowserToolSet(ToolDefinition[BrowserAction, BrowserObservation]):
593
719
  BrowserListTabsTool,
594
720
  BrowserSwitchTabTool,
595
721
  BrowserCloseTabTool,
722
+ BrowserGetStorageTool,
723
+ BrowserSetStorageTool,
596
724
  ]:
597
725
  tools.extend(tool_class.create(executor))
598
726
  return tools
@@ -214,11 +214,13 @@ class BrowserToolExecutor(ToolExecutor[BrowserAction, BrowserObservation]):
214
214
  BrowserCloseTabAction,
215
215
  BrowserGetContentAction,
216
216
  BrowserGetStateAction,
217
+ BrowserGetStorageAction,
217
218
  BrowserGoBackAction,
218
219
  BrowserListTabsAction,
219
220
  BrowserNavigateAction,
220
221
  BrowserObservation,
221
222
  BrowserScrollAction,
223
+ BrowserSetStorageAction,
222
224
  BrowserSwitchTabAction,
223
225
  BrowserTypeAction,
224
226
  )
@@ -234,6 +236,10 @@ class BrowserToolExecutor(ToolExecutor[BrowserAction, BrowserObservation]):
234
236
  result = await self.type_text(action.index, action.text)
235
237
  elif isinstance(action, BrowserGetStateAction):
236
238
  return await self.get_state(action.include_screenshot)
239
+ elif isinstance(action, BrowserGetStorageAction):
240
+ result = await self.get_storage()
241
+ elif isinstance(action, BrowserSetStorageAction):
242
+ result = await self.set_storage(action.storage_state)
237
243
  elif isinstance(action, BrowserGetContentAction):
238
244
  result = await self.get_content(
239
245
  action.extract_links, action.start_from_char
@@ -334,6 +340,16 @@ class BrowserToolExecutor(ToolExecutor[BrowserAction, BrowserObservation]):
334
340
  full_output_save_dir=self.full_output_save_dir,
335
341
  )
336
342
 
343
+ async def get_storage(self) -> str:
344
+ """Get browser storage (cookies, local storage, session storage)."""
345
+ await self._ensure_initialized()
346
+ return await self._server._get_storage()
347
+
348
+ async def set_storage(self, storage_state: dict) -> str:
349
+ """Set browser storage (cookies, local storage, session storage)."""
350
+ await self._ensure_initialized()
351
+ return await self._server._set_storage(storage_state)
352
+
337
353
  # Tab Management
338
354
  async def list_tabs(self) -> str:
339
355
  """List all open tabs."""
@@ -13,6 +13,96 @@ class CustomBrowserUseServer(LogSafeBrowserUseServer):
13
13
  page's content in markdown.
14
14
  """
15
15
 
16
+ async def _get_storage(self) -> str:
17
+ """Get browser storage (cookies, local storage, session storage)."""
18
+ import json
19
+
20
+ if not self.browser_session:
21
+ return "Error: No browser session active"
22
+
23
+ try:
24
+ # Use the private method from BrowserSession to get storage state
25
+ # This returns a dict with 'cookies' and 'origins'
26
+ # (localStorage/sessionStorage)
27
+ storage_state = await self.browser_session._cdp_get_storage_state()
28
+ return json.dumps(storage_state, indent=2)
29
+ except Exception as e:
30
+ logger.exception("Error getting storage state", exc_info=e)
31
+ return f"Error getting storage state: {str(e)}"
32
+
33
+ async def _set_storage(self, storage_state: dict) -> str:
34
+ """Set browser storage (cookies, local storage, session storage)."""
35
+ if not self.browser_session:
36
+ return "Error: No browser session active"
37
+
38
+ try:
39
+ # 1. Set cookies
40
+ cookies = storage_state.get("cookies", [])
41
+ if cookies:
42
+ await self.browser_session._cdp_set_cookies(cookies)
43
+
44
+ # 2. Set local/session storage
45
+ origins = storage_state.get("origins", [])
46
+ if origins:
47
+ cdp_session = await self.browser_session.get_or_create_cdp_session()
48
+
49
+ # Enable DOMStorage
50
+ await cdp_session.cdp_client.send.DOMStorage.enable(
51
+ session_id=cdp_session.session_id
52
+ )
53
+
54
+ try:
55
+ for origin_data in origins:
56
+ origin = origin_data.get("origin")
57
+ if not origin:
58
+ continue
59
+
60
+ dom_storage = cdp_session.cdp_client.send.DOMStorage
61
+
62
+ # Set localStorage
63
+ for item in origin_data.get("localStorage", []):
64
+ key = item.get("key") or item.get("name")
65
+ if not key:
66
+ continue
67
+ await dom_storage.setDOMStorageItem(
68
+ params={
69
+ "storageId": {
70
+ "securityOrigin": origin,
71
+ "isLocalStorage": True,
72
+ },
73
+ "key": key,
74
+ "value": item["value"],
75
+ },
76
+ session_id=cdp_session.session_id,
77
+ )
78
+
79
+ # Set sessionStorage
80
+ for item in origin_data.get("sessionStorage", []):
81
+ key = item.get("key") or item.get("name")
82
+ if not key:
83
+ continue
84
+ await dom_storage.setDOMStorageItem(
85
+ params={
86
+ "storageId": {
87
+ "securityOrigin": origin,
88
+ "isLocalStorage": False,
89
+ },
90
+ "key": key,
91
+ "value": item["value"],
92
+ },
93
+ session_id=cdp_session.session_id,
94
+ )
95
+ finally:
96
+ # Disable DOMStorage
97
+ await cdp_session.cdp_client.send.DOMStorage.disable(
98
+ session_id=cdp_session.session_id
99
+ )
100
+
101
+ return "Storage set successfully"
102
+ except Exception as e:
103
+ logger.exception("Error setting storage state", exc_info=e)
104
+ return f"Error setting storage state: {str(e)}"
105
+
16
106
  async def _get_content(self, extract_links=False, start_from_char: int = 0) -> str:
17
107
  MAX_CHAR_LIMIT = 30000
18
108
 
@@ -20,6 +20,7 @@ Notes:
20
20
 
21
21
  from .default import get_default_agent
22
22
  from .gemini import get_gemini_agent, get_gemini_tools
23
+ from .gpt5 import get_gpt5_agent
23
24
  from .planning import get_planning_agent
24
25
 
25
26
 
@@ -27,5 +28,6 @@ __all__ = [
27
28
  "get_default_agent",
28
29
  "get_gemini_agent",
29
30
  "get_gemini_tools",
31
+ "get_gpt5_agent",
30
32
  "get_planning_agent",
31
33
  ]
@@ -88,7 +88,8 @@ def get_gemini_agent(
88
88
  llm: LLM,
89
89
  cli_mode: bool = False,
90
90
  ) -> Agent:
91
- """Get an agent configured with gemini-style file editing tools."""
91
+ """Get an agent with gemini-style tools: read_file, write_file, edit,
92
+ list_directory."""
92
93
  tools = get_gemini_tools(
93
94
  enable_browser=not cli_mode,
94
95
  )
@@ -0,0 +1,75 @@
1
+ """GPT-5 preset configuration for OpenHands agents.
2
+
3
+ This preset uses ApplyPatchTool for file edits instead of the default
4
+ claude-style FileEditorTool. It mirrors the Gemini preset pattern by
5
+ providing optional helpers without changing global defaults.
6
+ """
7
+
8
+ from openhands.sdk import Agent
9
+ from openhands.sdk.context.condenser import LLMSummarizingCondenser
10
+ from openhands.sdk.context.condenser.base import CondenserBase
11
+ from openhands.sdk.llm.llm import LLM
12
+ from openhands.sdk.logger import get_logger
13
+ from openhands.sdk.tool import Tool
14
+
15
+
16
+ logger = get_logger(__name__)
17
+
18
+
19
+ def register_gpt5_tools(enable_browser: bool = True) -> None:
20
+ """Register the GPT-5 tool set (terminal, apply_patch, task_tracker, browser)."""
21
+ from openhands.tools.apply_patch import ApplyPatchTool
22
+ from openhands.tools.task_tracker import TaskTrackerTool
23
+ from openhands.tools.terminal import TerminalTool
24
+
25
+ logger.debug(f"Tool: {TerminalTool.name} registered.")
26
+ logger.debug(f"Tool: {ApplyPatchTool.name} registered.")
27
+ logger.debug(f"Tool: {TaskTrackerTool.name} registered.")
28
+
29
+ if enable_browser:
30
+ from openhands.tools.browser_use import BrowserToolSet
31
+
32
+ logger.debug(f"Tool: {BrowserToolSet.name} registered.")
33
+
34
+
35
+ def get_gpt5_tools(enable_browser: bool = True) -> list[Tool]:
36
+ """Get the GPT-5 tool specifications using ApplyPatchTool for edits.
37
+
38
+ Args:
39
+ enable_browser: Whether to include browser tools.
40
+ """
41
+ register_gpt5_tools(enable_browser=enable_browser)
42
+
43
+ from openhands.tools.apply_patch import ApplyPatchTool
44
+ from openhands.tools.task_tracker import TaskTrackerTool
45
+ from openhands.tools.terminal import TerminalTool
46
+
47
+ tools: list[Tool] = [
48
+ Tool(name=TerminalTool.name),
49
+ Tool(name=ApplyPatchTool.name),
50
+ Tool(name=TaskTrackerTool.name),
51
+ ]
52
+ if enable_browser:
53
+ from openhands.tools.browser_use import BrowserToolSet
54
+
55
+ tools.append(Tool(name=BrowserToolSet.name))
56
+ return tools
57
+
58
+
59
+ def get_gpt5_condenser(llm: LLM) -> CondenserBase:
60
+ """Get the default condenser for the GPT-5 preset."""
61
+ return LLMSummarizingCondenser(llm=llm, max_size=80, keep_first=4)
62
+
63
+
64
+ def get_gpt5_agent(llm: LLM, cli_mode: bool = False) -> Agent:
65
+ """Get an agent with ApplyPatchTool for unified-diff style file editing."""
66
+ tools = get_gpt5_tools(enable_browser=not cli_mode)
67
+ agent = Agent(
68
+ llm=llm,
69
+ tools=tools,
70
+ system_prompt_kwargs={"cli_mode": cli_mode},
71
+ condenser=get_gpt5_condenser(
72
+ llm=llm.model_copy(update={"usage_id": "condenser"})
73
+ ),
74
+ )
75
+ return agent
@@ -97,9 +97,11 @@ class TmuxTerminal(TerminalInterface):
97
97
  try:
98
98
  if hasattr(self, "session"):
99
99
  self.session.kill()
100
- except ImportError:
101
- # Python is shutting down, let the OS handle cleanup
102
- pass
100
+ except Exception as e:
101
+ # Session might already be dead/killed externally
102
+ # (e.g., "can't find session" error from tmux)
103
+ # Also handles ImportError during Python shutdown
104
+ logger.debug(f"Error closing tmux session (may already be dead): {e}")
103
105
  self._closed: bool = True
104
106
 
105
107
  def send_keys(self, text: str, enter: bool = True) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-tools
3
- Version: 1.7.1
3
+ Version: 1.7.3
4
4
  Summary: OpenHands Tools - Runtime tools for AI agents
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: openhands-sdk
@@ -3,12 +3,12 @@ openhands/tools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  openhands/tools/apply_patch/__init__.py,sha256=8FoATV60_WlXywmFwzSk8EDspBD6ZbLJFPJ8u_DcAM0,70
4
4
  openhands/tools/apply_patch/core.py,sha256=6AbpBlXj2l49MrxElSA3MGMq28XcILAjfIa3Mqx36uQ,16565
5
5
  openhands/tools/apply_patch/definition.py,sha256=V5_Yp64eeTGUMTKLwPhv6IFswb051gj9J4VZr-ulCjw,6374
6
- openhands/tools/browser_use/__init__.py,sha256=cbcgplzBnGgl6Y8poBcm0vWeZgZWoKuidGxr9j-vdSU,1315
7
- openhands/tools/browser_use/definition.py,sha256=9h9aWAzt4exO8M1d6BuA1W8dmrWFuGHvJQG1nOfL9iQ,19351
8
- openhands/tools/browser_use/impl.py,sha256=J4tG-YRXNT6KGnAIqctIknRE1_jt0FHlD5RqW4JTMwQ,15317
6
+ openhands/tools/browser_use/__init__.py,sha256=M8hf8hIjKZhgsxa186gw57t4cPg6JgHB9wyhMdEiA5Q,1547
7
+ openhands/tools/browser_use/definition.py,sha256=dcd9L6pTQkLV-iGzne6Yr6KIDK4itHNmEeFlOq5t4TA,23696
8
+ openhands/tools/browser_use/impl.py,sha256=Wl9_WHkTB35e_gFsC9nITsmKKTBMIvl46idUIQTXR4U,16085
9
9
  openhands/tools/browser_use/impl_windows.py,sha256=elnYUrIAnlqTyiBptLiDNyQepvDrzx5CehLvnXJBNqg,2587
10
10
  openhands/tools/browser_use/logging_fix.py,sha256=W2XQYnL9cHebG9MjUun4dGTmxaTSb2D_T5R-Kk-Vis4,1884
11
- openhands/tools/browser_use/server.py,sha256=diDUv9p8uZdt6kq9LzyogTADrSfsagqBnX8lpbOhIKA,3798
11
+ openhands/tools/browser_use/server.py,sha256=KQ_ULLQcJX0NtzWOUJUlppwKkZsHejT8ygHbLD40FRI,7720
12
12
  openhands/tools/delegate/__init__.py,sha256=Z3q2fvnkFp_n4FBN9KeZG70W-Ud_xUyaI8XUKrugDCs,511
13
13
  openhands/tools/delegate/definition.py,sha256=o3Jxiv5-fG3Om_PHgOCju0COuAtQ9Ylx5hJRxtqEV2g,3827
14
14
  openhands/tools/delegate/impl.py,sha256=sLVuGk5H6zQVj74DWazHhFioNN-sC5LAs-MxMo5z21A,11839
@@ -50,9 +50,10 @@ openhands/tools/grep/impl.py,sha256=Krbnygmqpv0iKI7HsfzIukOLoCweRg1JNCXv14d7WC8,
50
50
  openhands/tools/planning_file_editor/__init__.py,sha256=edIuvR5ZnEXXsYfRt8xbrq15Z6vtdUq4AMguuuk1grI,197
51
51
  openhands/tools/planning_file_editor/definition.py,sha256=7wzE1qXoengRq80MjDI-XbWhbPVYLU1lThFO9Mq14wg,3927
52
52
  openhands/tools/planning_file_editor/impl.py,sha256=W8Mdy7Qjbz90iKSmisw23-TcFtXwe7Vk373WvrScCS8,2218
53
- openhands/tools/preset/__init__.py,sha256=H9nGxiGHVKvywG2qpK3CCY03ow1bbmYFz33IQY79OWM,858
53
+ openhands/tools/preset/__init__.py,sha256=KougtVUTSj9D6AjR78EXmYRdITY6ZIaodCQuWfViXc0,913
54
54
  openhands/tools/preset/default.py,sha256=r6lAqHD-4ntjiOSfNvSxuAJtJqqTTik_mBIFZOE1w7Q,2686
55
- openhands/tools/preset/gemini.py,sha256=_JnmucroV1cJTNWCVG1qNIdIFaAiyvhiZd_RGw-TYvI,3111
55
+ openhands/tools/preset/gemini.py,sha256=FG3BcJjnm6tDLIjg6EiDFTksx5lVVBInh_Jpza0mHpU,3136
56
+ openhands/tools/preset/gpt5.py,sha256=44LOv6MncP9X9QU7pn1UfdjYl8ec8zKU9jUU7tUYR5I,2615
56
57
  openhands/tools/preset/planning.py,sha256=s05upBJ97JEZOfUJMkBW3xa5ZKgxZFklY1yHEBzqmhQ,5303
57
58
  openhands/tools/task_tracker/__init__.py,sha256=NVm3CE_CkIAUSjFexh7HLXMpibJ_Dh8J8OOow2SlE1I,302
58
59
  openhands/tools/task_tracker/definition.py,sha256=yGN_wks_-QpjRlfYiv5uOYyRTshaFuBwog0P62m5x0w,15772
@@ -66,14 +67,14 @@ openhands/tools/terminal/terminal/factory.py,sha256=9yjBU473_syYCQBZHSyDxhZL04Dn
66
67
  openhands/tools/terminal/terminal/interface.py,sha256=g0nyhMzVsIGptfBnBdv6FESUtv7k-EnRI32KYYl2VO0,6854
67
68
  openhands/tools/terminal/terminal/subprocess_terminal.py,sha256=zdSgjh4jo9aS-fseG0pfikDcF7QTHNbnr7OwtEQCEKA,16225
68
69
  openhands/tools/terminal/terminal/terminal_session.py,sha256=Y3n95JQfG_nid4g_j2873uVPjl-UQwiu3H3vwkijbrM,20159
69
- openhands/tools/terminal/terminal/tmux_terminal.py,sha256=GyD_FWhg5FT6Nx7GjNZkZGYxiAEsuu9_dXMe-rG4yxk,5926
70
+ openhands/tools/terminal/terminal/tmux_terminal.py,sha256=_Z3CqwC8czTX_XKF6eBnTcs5Zi94ElX-iRfJ071VtTo,6113
70
71
  openhands/tools/terminal/utils/command.py,sha256=ZT6KMFQNIpMMWGKnG8HAlCJpaB34JcbYYfYBjcLNTQs,5434
71
72
  openhands/tools/tom_consult/__init__.py,sha256=av9VYJRWHmP4_5Eu2840PARtgOTRP84jZjqJ3zs8sRs,581
72
73
  openhands/tools/tom_consult/definition.py,sha256=MTdOCOJaEGgOXhlJ9-x0HdhD6JiKNT2DodEOdsB4RBg,8224
73
74
  openhands/tools/tom_consult/executor.py,sha256=LkWeltj-7ZgLhVZKZP4cuhxqg2YuyRnqSz5S0U9WElk,16656
74
75
  openhands/tools/utils/__init__.py,sha256=AgJX59QLQTulZqIvJnUqM7LxAgsFhtqmgol-lKLc7Wc,1253
75
76
  openhands/tools/utils/timeout.py,sha256=AjKNLZa8NqQ0HllZzqWZwZMj-8PEWHHBXwOlMjTygpA,399
76
- openhands_tools-1.7.1.dist-info/METADATA,sha256=u24ULqypJtosRqHdeQJtcLfjSIjVQQ-cqqQNrQspgH8,418
77
- openhands_tools-1.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
- openhands_tools-1.7.1.dist-info/top_level.txt,sha256=jHgVu9I0Blam8BXFgedoGKfglPF8XvW1TsJFIjcgP4E,10
79
- openhands_tools-1.7.1.dist-info/RECORD,,
77
+ openhands_tools-1.7.3.dist-info/METADATA,sha256=064hgpA5Xj25XEwDYm4BW6FJiBMf9g6hLXSdWeNylSM,418
78
+ openhands_tools-1.7.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
79
+ openhands_tools-1.7.3.dist-info/top_level.txt,sha256=jHgVu9I0Blam8BXFgedoGKfglPF8XvW1TsJFIjcgP4E,10
80
+ openhands_tools-1.7.3.dist-info/RECORD,,