from openhands.core.logger import openhands_logger as logger from openhands.events.action.action import Action from openhands.events.event import Event, EventSource class ReplayManager: """ReplayManager manages the lifecycle of a replay session of a given trajectory. Replay manager keeps track of a list of events, replays actions, and ignore messages and observations. It could lead to unexpected or even errorneous results if any action is non-deterministic, or if the initial state before the replay session is different from the initial state of the trajectory. """ def __init__(self, replay_events: list[Event] | None): if replay_events: logger.info(f'Replay logs loaded, events length = {len(replay_events)}') self.replay_events = replay_events self.replay_mode = bool(replay_events) self.replay_index = 0 def _replayable(self) -> bool: return ( self.replay_events is not None and self.replay_index < len(self.replay_events) and isinstance(self.replay_events[self.replay_index], Action) and self.replay_events[self.replay_index].source != EventSource.USER ) def should_replay(self) -> bool: """ Whether the controller is in trajectory replay mode, and the replay hasn't finished. Note: after the replay is finished, the user and the agent could continue to message/act. This method also moves "replay_index" to the next action, if applicable. """ if not self.replay_mode: return False assert self.replay_events is not None while self.replay_index < len(self.replay_events) and not self._replayable(): self.replay_index += 1 return self._replayable() def step(self) -> Action: assert self.replay_events is not None event = self.replay_events[self.replay_index] assert isinstance(event, Action) self.replay_index += 1 return event