Spaces:
Build error
Build error
from dataclasses import dataclass, field | |
from enum import Enum | |
from typing import Any | |
from openhands.core.schema import ActionType | |
from openhands.events.action.action import Action | |
from openhands.events.event import RecallType | |
class ChangeAgentStateAction(Action): | |
"""Fake action, just to notify the client that a task state has changed.""" | |
agent_state: str | |
thought: str = '' | |
action: str = ActionType.CHANGE_AGENT_STATE | |
def message(self) -> str: | |
return f'Agent state changed to {self.agent_state}' | |
class AgentFinishTaskCompleted(Enum): | |
FALSE = 'false' | |
PARTIAL = 'partial' | |
TRUE = 'true' | |
class AgentFinishAction(Action): | |
"""An action where the agent finishes the task. | |
Attributes: | |
final_thought (str): The message to send to the user. | |
task_completed (enum): Whether the agent believes the task has been completed. | |
outputs (dict): The other outputs of the agent, for instance "content". | |
thought (str): The agent's explanation of its actions. | |
action (str): The action type, namely ActionType.FINISH. | |
""" | |
final_thought: str = '' | |
task_completed: AgentFinishTaskCompleted | None = None | |
outputs: dict[str, Any] = field(default_factory=dict) | |
thought: str = '' | |
action: str = ActionType.FINISH | |
def message(self) -> str: | |
if self.thought != '': | |
return self.thought | |
return "All done! What's next on the agenda?" | |
class AgentThinkAction(Action): | |
"""An action where the agent logs a thought. | |
Attributes: | |
thought (str): The agent's explanation of its actions. | |
action (str): The action type, namely ActionType.THINK. | |
""" | |
thought: str = '' | |
action: str = ActionType.THINK | |
def message(self) -> str: | |
return f'I am thinking...: {self.thought}' | |
class AgentRejectAction(Action): | |
outputs: dict = field(default_factory=dict) | |
thought: str = '' | |
action: str = ActionType.REJECT | |
def message(self) -> str: | |
msg: str = 'Task is rejected by the agent.' | |
if 'reason' in self.outputs: | |
msg += ' Reason: ' + self.outputs['reason'] | |
return msg | |
class AgentDelegateAction(Action): | |
agent: str | |
inputs: dict | |
thought: str = '' | |
action: str = ActionType.DELEGATE | |
def message(self) -> str: | |
return f"I'm asking {self.agent} for help with this task." | |
class RecallAction(Action): | |
"""This action is used for retrieving content, e.g., from the global directory or user workspace.""" | |
recall_type: RecallType | |
query: str = '' | |
thought: str = '' | |
action: str = ActionType.RECALL | |
def message(self) -> str: | |
return f'Retrieving content for: {self.query[:50]}' | |
def __str__(self) -> str: | |
ret = '**RecallAction**\n' | |
ret += f'QUERY: {self.query[:50]}' | |
return ret | |
class CondensationAction(Action): | |
"""This action indicates a condensation of the conversation history is happening. | |
There are two ways to specify the events to be forgotten: | |
1. By providing a list of event IDs. | |
2. By providing the start and end IDs of a range of events. | |
In the second case, we assume that event IDs are monotonically increasing, and that _all_ events between the start and end IDs are to be forgotten. | |
Raises: | |
ValueError: If the optional fields are not instantiated in a valid configuration. | |
""" | |
action: str = ActionType.CONDENSATION | |
forgotten_event_ids: list[int] | None = None | |
"""The IDs of the events that are being forgotten (removed from the `View` given to the LLM).""" | |
forgotten_events_start_id: int | None = None | |
"""The ID of the first event to be forgotten in a range of events.""" | |
forgotten_events_end_id: int | None = None | |
"""The ID of the last event to be forgotten in a range of events.""" | |
summary: str | None = None | |
"""An optional summary of the events being forgotten.""" | |
summary_offset: int | None = None | |
"""An optional offset to the start of the resulting view indicating where the summary should be inserted.""" | |
def _validate_field_polymorphism(self) -> bool: | |
"""Check if the optional fields are instantiated in a valid configuration.""" | |
# For the forgotton events, there are only two valid configurations: | |
# 1. We're forgetting events based on the list of provided IDs, or | |
using_event_ids = self.forgotten_event_ids is not None | |
# 2. We're forgetting events based on the range of IDs. | |
using_event_range = ( | |
self.forgotten_events_start_id is not None | |
and self.forgotten_events_end_id is not None | |
) | |
# Either way, we can only have one of the two valid configurations. | |
forgotten_event_configuration = using_event_ids ^ using_event_range | |
# We also need to check that if the summary is provided, so is the | |
# offset (and vice versa). | |
summary_configuration = ( | |
self.summary is None and self.summary_offset is None | |
) or (self.summary is not None and self.summary_offset is not None) | |
return forgotten_event_configuration and summary_configuration | |
def __post_init__(self): | |
if not self._validate_field_polymorphism(): | |
raise ValueError('Invalid configuration of the optional fields.') | |
def forgotten(self) -> list[int]: | |
"""The list of event IDs that should be forgotten.""" | |
# Start by making sure the fields are instantiated in a valid | |
# configuration. We check this whenever the event is initialized, but we | |
# can't make the dataclass immutable so we need to check it again here | |
# to make sure the configuration is still valid. | |
if not self._validate_field_polymorphism(): | |
raise ValueError('Invalid configuration of the optional fields.') | |
if self.forgotten_event_ids is not None: | |
return self.forgotten_event_ids | |
# If we've gotten this far, the start/end IDs are not None. | |
assert self.forgotten_events_start_id is not None | |
assert self.forgotten_events_end_id is not None | |
return list( | |
range(self.forgotten_events_start_id, self.forgotten_events_end_id + 1) | |
) | |
def message(self) -> str: | |
if self.summary: | |
return f'Summary: {self.summary}' | |
return f'Condenser is dropping the events: {self.forgotten}.' | |