Spaces:
Build error
Build error
| from typing import Any | |
| from openhands.core.exceptions import LLMMalformedActionError | |
| from openhands.events.action.action import Action | |
| from openhands.events.action.agent import ( | |
| AgentDelegateAction, | |
| AgentFinishAction, | |
| AgentRejectAction, | |
| AgentThinkAction, | |
| ChangeAgentStateAction, | |
| CondensationAction, | |
| RecallAction, | |
| ) | |
| from openhands.events.action.browse import BrowseInteractiveAction, BrowseURLAction | |
| from openhands.events.action.commands import ( | |
| CmdRunAction, | |
| IPythonRunCellAction, | |
| ) | |
| from openhands.events.action.empty import NullAction | |
| from openhands.events.action.files import ( | |
| FileEditAction, | |
| FileReadAction, | |
| FileWriteAction, | |
| ) | |
| from openhands.events.action.mcp import MCPAction | |
| from openhands.events.action.message import MessageAction, SystemMessageAction | |
| actions = ( | |
| NullAction, | |
| CmdRunAction, | |
| IPythonRunCellAction, | |
| BrowseURLAction, | |
| BrowseInteractiveAction, | |
| FileReadAction, | |
| FileWriteAction, | |
| FileEditAction, | |
| AgentThinkAction, | |
| AgentFinishAction, | |
| AgentRejectAction, | |
| AgentDelegateAction, | |
| RecallAction, | |
| ChangeAgentStateAction, | |
| MessageAction, | |
| SystemMessageAction, | |
| CondensationAction, | |
| MCPAction, | |
| ) | |
| ACTION_TYPE_TO_CLASS = {action_class.action: action_class for action_class in actions} # type: ignore[attr-defined] | |
| def handle_action_deprecated_args(args: dict[str, Any]) -> dict[str, Any]: | |
| # keep_prompt has been deprecated in https://github.com/All-Hands-AI/OpenHands/pull/4881 | |
| if 'keep_prompt' in args: | |
| args.pop('keep_prompt') | |
| # Handle translated_ipython_code deprecation | |
| if 'translated_ipython_code' in args: | |
| code = args.pop('translated_ipython_code') | |
| # Check if it's a file_editor call using a prefix check for efficiency | |
| file_editor_prefix = 'print(file_editor(**' | |
| if ( | |
| code is not None | |
| and code.startswith(file_editor_prefix) | |
| and code.endswith('))') | |
| ): | |
| try: | |
| # Extract and evaluate the dictionary string | |
| import ast | |
| # Extract the dictionary string between the prefix and the closing parentheses | |
| dict_str = code[len(file_editor_prefix) : -2] # Remove prefix and '))' | |
| file_args = ast.literal_eval(dict_str) | |
| # Update args with the extracted file editor arguments | |
| args.update(file_args) | |
| except (ValueError, SyntaxError): | |
| # If parsing fails, just remove the translated_ipython_code | |
| pass | |
| if args.get('command') == 'view': | |
| args.pop( | |
| 'command' | |
| ) # "view" will be translated to FileReadAction which doesn't have a command argument | |
| return args | |
| def action_from_dict(action: dict) -> Action: | |
| if not isinstance(action, dict): | |
| raise LLMMalformedActionError('action must be a dictionary') | |
| action = action.copy() | |
| if 'action' not in action: | |
| raise LLMMalformedActionError(f"'action' key is not found in {action=}") | |
| if not isinstance(action['action'], str): | |
| raise LLMMalformedActionError( | |
| f"'{action['action']=}' is not defined. Available actions: {ACTION_TYPE_TO_CLASS.keys()}" | |
| ) | |
| action_class = ACTION_TYPE_TO_CLASS.get(action['action']) | |
| if action_class is None: | |
| raise LLMMalformedActionError( | |
| f"'{action['action']=}' is not defined. Available actions: {ACTION_TYPE_TO_CLASS.keys()}" | |
| ) | |
| args = action.get('args', {}) | |
| # Remove timestamp from args if present | |
| timestamp = args.pop('timestamp', None) | |
| # compatibility for older event streams | |
| # is_confirmed has been renamed to confirmation_state | |
| is_confirmed = args.pop('is_confirmed', None) | |
| if is_confirmed is not None: | |
| args['confirmation_state'] = is_confirmed | |
| # images_urls has been renamed to image_urls | |
| if 'images_urls' in args: | |
| args['image_urls'] = args.pop('images_urls') | |
| # handle deprecated args | |
| args = handle_action_deprecated_args(args) | |
| try: | |
| decoded_action = action_class(**args) | |
| if 'timeout' in action: | |
| blocking = args.get('blocking', False) | |
| decoded_action.set_hard_timeout(action['timeout'], blocking=blocking) | |
| # Set timestamp if it was provided | |
| if timestamp: | |
| decoded_action._timestamp = timestamp | |
| except TypeError as e: | |
| raise LLMMalformedActionError( | |
| f'action={action} has the wrong arguments: {str(e)}' | |
| ) | |
| assert isinstance(decoded_action, Action) | |
| return decoded_action | |