Skip to content

Commit d343e4e

Browse files
authored
Config to save screenshots in trajectory (#7284)
1 parent 0fec237 commit d343e4e

File tree

5 files changed

+25
-8
lines changed

5 files changed

+25
-8
lines changed

config.template.toml

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ workspace_base = "./workspace"
4242
# If it's a folder, the session id will be used as the file name
4343
#save_trajectory_path="./trajectories"
4444

45+
# Whether to save screenshots in the trajectory
46+
# The screenshots are encoded and can make trajectory json files very large
47+
#save_screenshots_in_trajectory = false
48+
4549
# Path to replay a trajectory, must be a file path
4650
# If provided, trajectory will be loaded and replayed before the
4751
# agent responds to any user instruction

openhands/controller/agent_controller.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -897,10 +897,13 @@ def set_initial_state(
897897
# Always load from the event stream to avoid losing history
898898
self._init_history()
899899

900-
def get_trajectory(self) -> list[dict]:
900+
def get_trajectory(self, include_screenshots: bool = False) -> list[dict]:
901901
# state history could be partially hidden/truncated before controller is closed
902902
assert self._closed
903-
return [event_to_trajectory(event) for event in self.state.history]
903+
return [
904+
event_to_trajectory(event, include_screenshots)
905+
for event in self.state.history
906+
]
904907

905908
def _init_history(self) -> None:
906909
"""Initializes the agent's history from the event stream.

openhands/core/config/app_config.py

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class AppConfig(BaseModel):
2929
file_store: Type of file store to use.
3030
file_store_path: Path to the file store.
3131
save_trajectory_path: Either a folder path to store trajectories with auto-generated filenames, or a designated trajectory file path.
32+
save_screenshots_in_trajectory: Whether to save screenshots in trajectory (in encoded image format).
3233
replay_trajectory_path: Path to load trajectory and replay. If provided, trajectory would be replayed first before user's instruction.
3334
workspace_base: Base path for the workspace. Defaults to `./workspace` as absolute path.
3435
workspace_mount_path: Path to mount the workspace. Defaults to `workspace_base`.
@@ -58,6 +59,7 @@ class AppConfig(BaseModel):
5859
file_store: str = Field(default='local')
5960
file_store_path: str = Field(default='/tmp/openhands_file_store')
6061
save_trajectory_path: str | None = Field(default=None)
62+
save_screenshots_in_trajectory: bool = Field(default=False)
6163
replay_trajectory_path: str | None = Field(default=None)
6264
workspace_base: str | None = Field(default=None)
6365
workspace_mount_path: str | None = Field(default=None)

openhands/core/main.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,9 @@ def on_event(event: Event):
210210
else:
211211
file_path = config.save_trajectory_path
212212
os.makedirs(os.path.dirname(file_path), exist_ok=True)
213-
histories = controller.get_trajectory()
213+
histories = controller.get_trajectory(config.save_screenshots_in_trajectory)
214214
with open(file_path, 'w') as f:
215-
json.dump(histories, f)
215+
json.dump(histories, f, indent=4)
216216

217217
return state
218218

openhands/events/serialization/event.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from pydantic import BaseModel
66

77
from openhands.events import Event, EventSource
8-
from openhands.events.observation.observation import Observation
98
from openhands.events.serialization.action import action_from_dict
109
from openhands.events.serialization.observation import observation_from_dict
1110
from openhands.events.serialization.utils import remove_fields
@@ -34,7 +33,6 @@
3433
]
3534

3635
DELETE_FROM_TRAJECTORY_EXTRAS = {
37-
'screenshot',
3836
'dom_object',
3937
'axtree_object',
4038
'active_page_index',
@@ -44,6 +42,11 @@
4442
'extra_element_properties',
4543
}
4644

45+
DELETE_FROM_TRAJECTORY_EXTRAS_AND_SCREENSHOTS = DELETE_FROM_TRAJECTORY_EXTRAS | {
46+
'screenshot',
47+
'set_of_marks',
48+
}
49+
4750

4851
def event_from_dict(data) -> 'Event':
4952
evt: Event
@@ -133,10 +136,15 @@ def event_to_dict(event: 'Event') -> dict:
133136
return d
134137

135138

136-
def event_to_trajectory(event: 'Event') -> dict:
139+
def event_to_trajectory(event: 'Event', include_screenshots: bool = False) -> dict:
137140
d = event_to_dict(event)
138141
if 'extras' in d:
139-
remove_fields(d['extras'], DELETE_FROM_TRAJECTORY_EXTRAS)
142+
remove_fields(
143+
d['extras'],
144+
DELETE_FROM_TRAJECTORY_EXTRAS
145+
if include_screenshots
146+
else DELETE_FROM_TRAJECTORY_EXTRAS_AND_SCREENSHOTS,
147+
)
140148
return d
141149

142150

0 commit comments

Comments
 (0)