mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
Refactor actions and observations (#1479)
* refactor actions and events * remove type_key * remove stream * move import * move import * fix NullObs * reorder imports * fix lint * fix dataclasses * remove blank fields * fix nullobs * fix sidebar labels * fix test compilation * switch to asdict * lint * fix whitespace * fix executable * delint * fix run * remove NotImplementeds * fix path prefix * remove null files * add debug * add more debug info * fix dataclass on null * remove debug * revert sandbox * fix merge issues * fix tyeps * Update opendevin/events/action/browse.py
This commit is contained in:
parent
f19333aa6e
commit
ce7c7eaae4
@ -1,14 +1,14 @@
|
||||
from typing import List
|
||||
|
||||
from opendevin.action import (
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
AgentThinkAction,
|
||||
FileReadAction,
|
||||
FileWriteAction,
|
||||
)
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.events.observation import Observation
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.observation import Observation
|
||||
from opendevin.state import State
|
||||
|
||||
from .parser import parse_command
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import re
|
||||
|
||||
from opendevin.action import (
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
AgentEchoAction,
|
||||
AgentFinishAction,
|
||||
|
||||
@ -2,7 +2,8 @@ import re
|
||||
from typing import List, Mapping
|
||||
|
||||
from agenthub.codeact_agent.prompt import EXAMPLES, SYSTEM_MESSAGE
|
||||
from opendevin.action import (
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
AgentEchoAction,
|
||||
AgentFinishAction,
|
||||
@ -11,14 +12,13 @@ from opendevin.action import (
|
||||
IPythonRunCellAction,
|
||||
NullAction,
|
||||
)
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
AgentMessageObservation,
|
||||
CmdOutputObservation,
|
||||
IPythonRunCellObservation,
|
||||
UserMessageObservation,
|
||||
)
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.sandbox.plugins import (
|
||||
JupyterRequirement,
|
||||
PluginRequirement,
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
from typing import List
|
||||
|
||||
from opendevin.action import Action, AgentDelegateAction, AgentFinishAction
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.events.action import Action, AgentDelegateAction, AgentFinishAction
|
||||
from opendevin.events.observation import AgentDelegateObservation
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.observation import AgentDelegateObservation
|
||||
from opendevin.state import State
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import time
|
||||
from typing import List, TypedDict
|
||||
|
||||
from opendevin.action import (
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
AddTaskAction,
|
||||
AgentFinishAction,
|
||||
@ -13,9 +14,7 @@ from opendevin.action import (
|
||||
FileWriteAction,
|
||||
ModifyTaskAction,
|
||||
)
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
AgentRecallObservation,
|
||||
CmdOutputObservation,
|
||||
FileReadObservation,
|
||||
@ -23,6 +22,7 @@ from opendevin.observation import (
|
||||
NullObservation,
|
||||
Observation,
|
||||
)
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.state import State
|
||||
|
||||
"""
|
||||
|
||||
@ -3,8 +3,8 @@ from typing import Dict, List
|
||||
|
||||
from jinja2 import BaseLoader, Environment
|
||||
|
||||
from opendevin.action import Action, action_from_dict
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.events.action import Action, action_from_dict
|
||||
from opendevin.exceptions import LLMOutputError
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.state import State
|
||||
|
||||
@ -3,7 +3,8 @@ from typing import List
|
||||
import agenthub.monologue_agent.utils.prompts as prompts
|
||||
from agenthub.monologue_agent.utils.monologue import Monologue
|
||||
from opendevin import config
|
||||
from opendevin.action import (
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
AgentRecallAction,
|
||||
AgentThinkAction,
|
||||
@ -14,10 +15,7 @@ from opendevin.action import (
|
||||
GitHubPushAction,
|
||||
NullAction,
|
||||
)
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.exceptions import AgentNoInstructionError
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
AgentRecallObservation,
|
||||
BrowserOutputObservation,
|
||||
CmdOutputObservation,
|
||||
@ -25,6 +23,8 @@ from opendevin.observation import (
|
||||
NullObservation,
|
||||
Observation,
|
||||
)
|
||||
from opendevin.exceptions import AgentNoInstructionError
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.schema import ActionType
|
||||
from opendevin.schema.config import ConfigType
|
||||
from opendevin.state import State
|
||||
|
||||
@ -3,14 +3,14 @@ from json import JSONDecodeError
|
||||
from typing import List
|
||||
|
||||
from opendevin import config
|
||||
from opendevin.action import (
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
action_from_dict,
|
||||
)
|
||||
from opendevin.exceptions import LLMOutputError
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
CmdOutputObservation,
|
||||
)
|
||||
from opendevin.exceptions import LLMOutputError
|
||||
from opendevin.schema.config import ConfigType
|
||||
|
||||
from . import json
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from typing import List
|
||||
|
||||
from opendevin.action import Action, AgentFinishAction
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.events.action import Action, AgentFinishAction
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.state import State
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import json
|
||||
from typing import Dict, List, Tuple, Type
|
||||
|
||||
from opendevin.action import (
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
AddTaskAction,
|
||||
AgentFinishAction,
|
||||
@ -17,11 +17,11 @@ from opendevin.action import (
|
||||
NullAction,
|
||||
action_from_dict,
|
||||
)
|
||||
from opendevin.logger import opendevin_logger as logger
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
NullObservation,
|
||||
Observation,
|
||||
)
|
||||
from opendevin.logger import opendevin_logger as logger
|
||||
from opendevin.plan import Plan
|
||||
from opendevin.schema import ActionType
|
||||
|
||||
|
||||
9
docs/modules/python/opendevin/events/action/__init__.md
Normal file
9
docs/modules/python/opendevin/events/action/__init__.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
sidebar_label: action
|
||||
title: opendevin.events.action
|
||||
---
|
||||
|
||||
#### ACTION\_TYPE\_TO\_CLASS
|
||||
|
||||
type: ignore[attr-defined]
|
||||
|
||||
14
docs/modules/python/opendevin/events/action/empty.md
Normal file
14
docs/modules/python/opendevin/events/action/empty.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
sidebar_label: empty
|
||||
title: opendevin.events.action.empty
|
||||
---
|
||||
|
||||
## NullAction Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class NullAction(Action)
|
||||
```
|
||||
|
||||
An action that does nothing.
|
||||
|
||||
16
docs/modules/python/opendevin/events/action/files.md
Normal file
16
docs/modules/python/opendevin/events/action/files.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
sidebar_label: files
|
||||
title: opendevin.events.action.files
|
||||
---
|
||||
|
||||
## FileReadAction Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class FileReadAction(Action)
|
||||
```
|
||||
|
||||
Reads a file from a given path.
|
||||
Can be set to read specific lines using start and end
|
||||
Default lines 0:-1 (whole file)
|
||||
|
||||
46
docs/modules/python/opendevin/events/action/github.md
Normal file
46
docs/modules/python/opendevin/events/action/github.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
sidebar_label: github
|
||||
title: opendevin.events.action.github
|
||||
---
|
||||
|
||||
## GitHubPushAction Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class GitHubPushAction(Action)
|
||||
```
|
||||
|
||||
This pushes the current branch to github.
|
||||
|
||||
To use this, you need to set the GITHUB_TOKEN environment variable.
|
||||
The agent will return a message with a URL that you can click to make a pull
|
||||
request.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `owner` - The owner of the source repo
|
||||
- `repo` - The name of the source repo
|
||||
- `branch` - The branch to push
|
||||
- `action` - The action identifier
|
||||
|
||||
## GitHubSendPRAction Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class GitHubSendPRAction(Action)
|
||||
```
|
||||
|
||||
An action to send a github PR.
|
||||
|
||||
To use this, you need to set the GITHUB_TOKEN environment variable.
|
||||
|
||||
**Attributes**:
|
||||
|
||||
- `owner` - The owner of the source repo
|
||||
- `repo` - The name of the source repo
|
||||
- `title` - The title of the PR
|
||||
- `head` - The branch to send the PR from
|
||||
- `head_repo` - The repo to send the PR from
|
||||
- `base` - The branch to send the PR to
|
||||
- `body` - The body of the PR
|
||||
|
||||
14
docs/modules/python/opendevin/events/action/tasks.md
Normal file
14
docs/modules/python/opendevin/events/action/tasks.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
sidebar_label: tasks
|
||||
title: opendevin.events.action.tasks
|
||||
---
|
||||
|
||||
## TaskStateChangedAction Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TaskStateChangedAction(Action)
|
||||
```
|
||||
|
||||
Fake action, just to notify the client that a task state has changed.
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
---
|
||||
sidebar_label: observation
|
||||
title: opendevin.events.observation
|
||||
---
|
||||
|
||||
#### OBSERVATION\_TYPE\_TO\_CLASS
|
||||
|
||||
type: ignore[attr-defined]
|
||||
|
||||
14
docs/modules/python/opendevin/events/observation/browse.md
Normal file
14
docs/modules/python/opendevin/events/observation/browse.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
sidebar_label: browse
|
||||
title: opendevin.events.observation.browse
|
||||
---
|
||||
|
||||
## BrowserOutputObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class BrowserOutputObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents the output of a browser.
|
||||
|
||||
23
docs/modules/python/opendevin/events/observation/commands.md
Normal file
23
docs/modules/python/opendevin/events/observation/commands.md
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
sidebar_label: commands
|
||||
title: opendevin.events.observation.commands
|
||||
---
|
||||
|
||||
## CmdOutputObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class CmdOutputObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents the output of a command.
|
||||
|
||||
## IPythonRunCellObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class IPythonRunCellObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents the output of a IPythonRunCellAction.
|
||||
|
||||
14
docs/modules/python/opendevin/events/observation/delegate.md
Normal file
14
docs/modules/python/opendevin/events/observation/delegate.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
sidebar_label: delegate
|
||||
title: opendevin.events.observation.delegate
|
||||
---
|
||||
|
||||
## AgentDelegateObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class AgentDelegateObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents the result from delegating to another agent
|
||||
|
||||
15
docs/modules/python/opendevin/events/observation/empty.md
Normal file
15
docs/modules/python/opendevin/events/observation/empty.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
sidebar_label: empty
|
||||
title: opendevin.events.observation.empty
|
||||
---
|
||||
|
||||
## NullObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class NullObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents a null observation.
|
||||
This is used when the produced action is NOT executable.
|
||||
|
||||
14
docs/modules/python/opendevin/events/observation/error.md
Normal file
14
docs/modules/python/opendevin/events/observation/error.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
sidebar_label: error
|
||||
title: opendevin.events.observation.error
|
||||
---
|
||||
|
||||
## AgentErrorObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class AgentErrorObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents an error encountered by the agent.
|
||||
|
||||
23
docs/modules/python/opendevin/events/observation/files.md
Normal file
23
docs/modules/python/opendevin/events/observation/files.md
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
sidebar_label: files
|
||||
title: opendevin.events.observation.files
|
||||
---
|
||||
|
||||
## FileReadObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class FileReadObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents the content of a file.
|
||||
|
||||
## FileWriteObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class FileWriteObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents a file write operation
|
||||
|
||||
23
docs/modules/python/opendevin/events/observation/message.md
Normal file
23
docs/modules/python/opendevin/events/observation/message.md
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
sidebar_label: message
|
||||
title: opendevin.events.observation.message
|
||||
---
|
||||
|
||||
## UserMessageObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class UserMessageObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents a message sent by the user.
|
||||
|
||||
## AgentMessageObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class AgentMessageObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents a message sent by the agent.
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
---
|
||||
sidebar_label: observation
|
||||
title: opendevin.events.observation.observation
|
||||
---
|
||||
|
||||
## Observation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Observation(Event)
|
||||
```
|
||||
|
||||
#### to\_memory
|
||||
|
||||
```python
|
||||
def to_memory() -> dict
|
||||
```
|
||||
|
||||
Converts the observation to a dictionary.
|
||||
|
||||
14
docs/modules/python/opendevin/events/observation/recall.md
Normal file
14
docs/modules/python/opendevin/events/observation/recall.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
sidebar_label: recall
|
||||
title: opendevin.events.observation.recall
|
||||
---
|
||||
|
||||
## AgentRecallObservation Objects
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class AgentRecallObservation(Observation)
|
||||
```
|
||||
|
||||
This data class represents a list of memories recalled by the agent.
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
from dataclasses import asdict, dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from opendevin.schema import ActionType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opendevin.controller import AgentController
|
||||
from opendevin.observation import Observation
|
||||
|
||||
|
||||
@dataclass
|
||||
class Action:
|
||||
async def run(self, controller: 'AgentController') -> 'Observation':
|
||||
raise NotImplementedError
|
||||
|
||||
def to_memory(self):
|
||||
d = asdict(self)
|
||||
try:
|
||||
v = d.pop('action')
|
||||
except KeyError:
|
||||
raise NotImplementedError(f'{self=} does not have action attribute set')
|
||||
return {'action': v, 'args': d}
|
||||
|
||||
def to_dict(self):
|
||||
d = self.to_memory()
|
||||
d['message'] = self.message
|
||||
return d
|
||||
|
||||
@property
|
||||
def executable(self) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExecutableAction(Action):
|
||||
@property
|
||||
def executable(self) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
@dataclass
|
||||
class NotExecutableAction(Action):
|
||||
@property
|
||||
def executable(self) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
@dataclass
|
||||
class NullAction(NotExecutableAction):
|
||||
"""An action that does nothing.
|
||||
"""
|
||||
|
||||
action: str = ActionType.NULL
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
return 'No action'
|
||||
@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Dict, List, Type
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opendevin.action import Action
|
||||
from opendevin.events.action import Action
|
||||
from opendevin.state import State
|
||||
from opendevin.exceptions import AgentAlreadyRegisteredError, AgentNotRegisteredError
|
||||
from opendevin.llm.llm import LLM
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
from typing import List
|
||||
|
||||
from opendevin import config
|
||||
from opendevin.action import (
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
)
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
AgentErrorObservation,
|
||||
CmdOutputObservation,
|
||||
NullObservation,
|
||||
Observation,
|
||||
)
|
||||
from opendevin.sandbox import DockerExecBox, DockerSSHBox, E2BBox, LocalBox, Sandbox
|
||||
@ -43,9 +42,6 @@ class ActionManager:
|
||||
self.sandbox.init_plugins(plugins)
|
||||
|
||||
async def run_action(self, action: Action, agent_controller) -> Observation:
|
||||
observation: Observation = NullObservation('')
|
||||
if not action.executable:
|
||||
return observation
|
||||
observation = await action.run(agent_controller)
|
||||
return observation
|
||||
|
||||
|
||||
@ -3,14 +3,23 @@ from typing import Callable, List, Type
|
||||
|
||||
from agenthub.codeact_agent.codeact_agent import CodeActAgent
|
||||
from opendevin import config
|
||||
from opendevin.action import (
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.controller.action_manager import ActionManager
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
AgentDelegateAction,
|
||||
AgentFinishAction,
|
||||
AgentTalkAction,
|
||||
NullAction,
|
||||
TaskStateChangedAction,
|
||||
)
|
||||
from opendevin.events.observation import (
|
||||
AgentDelegateObservation,
|
||||
AgentErrorObservation,
|
||||
NullObservation,
|
||||
Observation,
|
||||
UserMessageObservation,
|
||||
)
|
||||
from opendevin.action.tasks import TaskStateChangedAction
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.browser.browser_env import BrowserEnv
|
||||
from opendevin.controller.action_manager import ActionManager
|
||||
@ -21,13 +30,6 @@ from opendevin.exceptions import (
|
||||
MaxCharsExceedError,
|
||||
)
|
||||
from opendevin.logger import opendevin_logger as logger
|
||||
from opendevin.observation import (
|
||||
AgentDelegateObservation,
|
||||
AgentErrorObservation,
|
||||
NullObservation,
|
||||
Observation,
|
||||
UserMessageObservation,
|
||||
)
|
||||
from opendevin.plan import Plan
|
||||
from opendevin.sandbox import DockerSSHBox
|
||||
from opendevin.schema import TaskState
|
||||
|
||||
0
opendevin/events/__init__.py
Normal file
0
opendevin/events/__init__.py
Normal file
@ -1,4 +1,7 @@
|
||||
from ..exceptions import AgentMalformedActionError
|
||||
|
||||
from opendevin.exceptions import AgentMalformedActionError
|
||||
|
||||
from .action import Action
|
||||
from .agent import (
|
||||
AgentDelegateAction,
|
||||
AgentEchoAction,
|
||||
@ -8,12 +11,12 @@ from .agent import (
|
||||
AgentTalkAction,
|
||||
AgentThinkAction,
|
||||
)
|
||||
from .base import Action, NullAction
|
||||
from .bash import CmdKillAction, CmdRunAction, IPythonRunCellAction
|
||||
from .browse import BrowseURLAction
|
||||
from .fileop import FileReadAction, FileWriteAction
|
||||
from .commands import CmdKillAction, CmdRunAction, IPythonRunCellAction
|
||||
from .empty import NullAction
|
||||
from .files import FileReadAction, FileWriteAction
|
||||
from .github import GitHubPushAction
|
||||
from .tasks import AddTaskAction, ModifyTaskAction
|
||||
from .tasks import AddTaskAction, ModifyTaskAction, TaskStateChangedAction
|
||||
|
||||
actions = (
|
||||
CmdKillAction,
|
||||
@ -29,6 +32,7 @@ actions = (
|
||||
AgentDelegateAction,
|
||||
AddTaskAction,
|
||||
ModifyTaskAction,
|
||||
TaskStateChangedAction,
|
||||
GitHubPushAction,
|
||||
)
|
||||
|
||||
@ -71,5 +75,6 @@ __all__ = [
|
||||
'AgentSummarizeAction',
|
||||
'AddTaskAction',
|
||||
'ModifyTaskAction',
|
||||
'TaskStateChangedAction',
|
||||
'IPythonRunCellAction'
|
||||
]
|
||||
22
opendevin/events/action/action.py
Normal file
22
opendevin/events/action/action.py
Normal file
@ -0,0 +1,22 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from opendevin.events.event import Event
|
||||
from opendevin.events.observation import NullObservation, Observation
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opendevin.controller import AgentController
|
||||
|
||||
|
||||
@dataclass
|
||||
class Action(Event):
|
||||
async def run(self, controller: 'AgentController') -> 'Observation':
|
||||
return NullObservation('')
|
||||
|
||||
def to_memory(self):
|
||||
d = super().to_memory()
|
||||
try:
|
||||
v = d.pop('action')
|
||||
except KeyError:
|
||||
raise NotImplementedError(f'{self=} does not have action attribute set')
|
||||
return {'action': v, 'args': d}
|
||||
@ -1,7 +1,7 @@
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING, Dict
|
||||
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
AgentMessageObservation,
|
||||
AgentRecallObservation,
|
||||
NullObservation,
|
||||
@ -9,14 +9,14 @@ from opendevin.observation import (
|
||||
)
|
||||
from opendevin.schema import ActionType
|
||||
|
||||
from .base import ExecutableAction, NotExecutableAction
|
||||
from .action import Action
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opendevin.controller import AgentController
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentRecallAction(ExecutableAction):
|
||||
class AgentRecallAction(Action):
|
||||
query: str
|
||||
thought: str = ''
|
||||
action: str = ActionType.RECALL
|
||||
@ -33,24 +33,21 @@ class AgentRecallAction(ExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentThinkAction(NotExecutableAction):
|
||||
class AgentThinkAction(Action):
|
||||
thought: str
|
||||
action: str = ActionType.THINK
|
||||
|
||||
async def run(self, controller: 'AgentController') -> 'Observation':
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
return self.thought
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentTalkAction(NotExecutableAction):
|
||||
class AgentTalkAction(Action):
|
||||
content: str
|
||||
action: str = ActionType.TALK
|
||||
|
||||
async def run(self, controller: 'AgentController') -> 'Observation':
|
||||
async def run(self, controller: 'AgentController') -> Observation:
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@ -62,11 +59,11 @@ class AgentTalkAction(NotExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentEchoAction(ExecutableAction):
|
||||
class AgentEchoAction(Action):
|
||||
content: str
|
||||
action: str = 'echo'
|
||||
|
||||
async def run(self, controller: 'AgentController') -> 'Observation':
|
||||
async def run(self, controller: 'AgentController') -> Observation:
|
||||
return AgentMessageObservation(self.content)
|
||||
|
||||
@property
|
||||
@ -75,7 +72,7 @@ class AgentEchoAction(ExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentSummarizeAction(NotExecutableAction):
|
||||
class AgentSummarizeAction(Action):
|
||||
summary: str
|
||||
action: str = ActionType.SUMMARIZE
|
||||
|
||||
@ -85,27 +82,24 @@ class AgentSummarizeAction(NotExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentFinishAction(NotExecutableAction):
|
||||
class AgentFinishAction(Action):
|
||||
outputs: Dict = field(default_factory=dict)
|
||||
thought: str = ''
|
||||
action: str = ActionType.FINISH
|
||||
|
||||
async def run(self, controller: 'AgentController') -> 'Observation':
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
return "All done! What's next on the agenda?"
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentDelegateAction(ExecutableAction):
|
||||
class AgentDelegateAction(Action):
|
||||
agent: str
|
||||
inputs: dict
|
||||
thought: str = ''
|
||||
action: str = ActionType.DELEGATE
|
||||
|
||||
async def run(self, controller: 'AgentController') -> 'Observation':
|
||||
async def run(self, controller: 'AgentController') -> Observation:
|
||||
await controller.start_delegate(self)
|
||||
return NullObservation('')
|
||||
|
||||
@ -2,17 +2,18 @@ import os
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from opendevin.observation import BrowserOutputObservation
|
||||
|
||||
from opendevin.events.observation import BrowserOutputObservation
|
||||
from opendevin.schema import ActionType
|
||||
|
||||
from .base import ExecutableAction
|
||||
from .action import Action
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opendevin.controller import AgentController
|
||||
|
||||
|
||||
@dataclass
|
||||
class BrowseURLAction(ExecutableAction):
|
||||
class BrowseURLAction(Action):
|
||||
url: str
|
||||
thought: str = ''
|
||||
action: str = ActionType.BROWSE
|
||||
@ -6,17 +6,17 @@ from typing import TYPE_CHECKING
|
||||
from opendevin import config
|
||||
from opendevin.schema import ActionType, ConfigType
|
||||
|
||||
from .base import ExecutableAction
|
||||
from .action import Action
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opendevin.controller import AgentController
|
||||
from opendevin.observation import CmdOutputObservation, Observation
|
||||
from opendevin.events.observation import CmdOutputObservation, Observation
|
||||
|
||||
from opendevin.observation import IPythonRunCellObservation
|
||||
from opendevin.events.observation import IPythonRunCellObservation
|
||||
|
||||
|
||||
@dataclass
|
||||
class CmdRunAction(ExecutableAction):
|
||||
class CmdRunAction(Action):
|
||||
command: str
|
||||
background: bool = False
|
||||
thought: str = ''
|
||||
@ -38,7 +38,7 @@ class CmdRunAction(ExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class CmdKillAction(ExecutableAction):
|
||||
class CmdKillAction(Action):
|
||||
id: int
|
||||
thought: str = ''
|
||||
action: str = ActionType.KILL
|
||||
@ -55,7 +55,7 @@ class CmdKillAction(ExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class IPythonRunCellAction(ExecutableAction):
|
||||
class IPythonRunCellAction(Action):
|
||||
code: str
|
||||
thought: str = ''
|
||||
action: str = ActionType.RUN_IPYTHON
|
||||
16
opendevin/events/action/empty.py
Normal file
16
opendevin/events/action/empty.py
Normal file
@ -0,0 +1,16 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from opendevin.schema import ActionType
|
||||
|
||||
from .action import Action
|
||||
|
||||
|
||||
@dataclass
|
||||
class NullAction(Action):
|
||||
"""An action that does nothing.
|
||||
"""
|
||||
action: str = ActionType.NULL
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
return 'No action'
|
||||
@ -3,7 +3,7 @@ from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from opendevin import config
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
AgentErrorObservation,
|
||||
FileReadObservation,
|
||||
FileWriteObservation,
|
||||
@ -13,7 +13,7 @@ from opendevin.sandbox import E2BBox
|
||||
from opendevin.schema import ActionType
|
||||
from opendevin.schema.config import ConfigType
|
||||
|
||||
from .base import ExecutableAction
|
||||
from .action import Action
|
||||
|
||||
|
||||
def resolve_path(file_path, working_directory):
|
||||
@ -41,7 +41,7 @@ def resolve_path(file_path, working_directory):
|
||||
|
||||
|
||||
@dataclass
|
||||
class FileReadAction(ExecutableAction):
|
||||
class FileReadAction(Action):
|
||||
"""
|
||||
Reads a file from a given path.
|
||||
Can be set to read specific lines using start and end
|
||||
@ -95,7 +95,7 @@ class FileReadAction(ExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class FileWriteAction(ExecutableAction):
|
||||
class FileWriteAction(Action):
|
||||
path: str
|
||||
content: str
|
||||
start: int = 0
|
||||
@ -6,20 +6,23 @@ from typing import TYPE_CHECKING
|
||||
import requests
|
||||
|
||||
from opendevin import config
|
||||
from opendevin.observation import AgentErrorObservation, Observation
|
||||
from opendevin.observation.message import AgentMessageObservation
|
||||
from opendevin.observation.run import CmdOutputObservation
|
||||
from opendevin.events.observation import (
|
||||
AgentErrorObservation,
|
||||
AgentMessageObservation,
|
||||
CmdOutputObservation,
|
||||
Observation,
|
||||
)
|
||||
from opendevin.schema import ActionType
|
||||
from opendevin.schema.config import ConfigType
|
||||
|
||||
from .base import ExecutableAction
|
||||
from .action import Action
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opendevin.controller import AgentController
|
||||
|
||||
|
||||
@dataclass
|
||||
class GitHubPushAction(ExecutableAction):
|
||||
class GitHubPushAction(Action):
|
||||
"""This pushes the current branch to github.
|
||||
|
||||
To use this, you need to set the GITHUB_TOKEN environment variable.
|
||||
@ -85,7 +88,7 @@ class GitHubPushAction(ExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class GitHubSendPRAction(ExecutableAction):
|
||||
class GitHubSendPRAction(Action):
|
||||
"""An action to send a github PR.
|
||||
|
||||
To use this, you need to set the GITHUB_TOKEN environment variable.
|
||||
@ -1,17 +1,17 @@
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from opendevin.observation import NullObservation
|
||||
from opendevin.events.observation import NullObservation
|
||||
from opendevin.schema import ActionType
|
||||
|
||||
from .base import ExecutableAction, NotExecutableAction
|
||||
from .action import Action
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opendevin.controller import AgentController
|
||||
|
||||
|
||||
@dataclass
|
||||
class AddTaskAction(ExecutableAction):
|
||||
class AddTaskAction(Action):
|
||||
parent: str
|
||||
goal: str
|
||||
subtasks: list = field(default_factory=list)
|
||||
@ -29,7 +29,7 @@ class AddTaskAction(ExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModifyTaskAction(ExecutableAction):
|
||||
class ModifyTaskAction(Action):
|
||||
id: str
|
||||
state: str
|
||||
thought: str = ''
|
||||
@ -46,7 +46,7 @@ class ModifyTaskAction(ExecutableAction):
|
||||
|
||||
|
||||
@dataclass
|
||||
class TaskStateChangedAction(NotExecutableAction):
|
||||
class TaskStateChangedAction(Action):
|
||||
"""Fake action, just to notify the client that a task state has changed."""
|
||||
task_state: str
|
||||
thought: str = ''
|
||||
16
opendevin/events/event.py
Normal file
16
opendevin/events/event.py
Normal file
@ -0,0 +1,16 @@
|
||||
from dataclasses import asdict, dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Event:
|
||||
def to_memory(self):
|
||||
return asdict(self)
|
||||
|
||||
def to_dict(self):
|
||||
d = self.to_memory()
|
||||
d['message'] = self.message
|
||||
return d
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
return self.message
|
||||
@ -1,11 +1,12 @@
|
||||
from .base import NullObservation, Observation
|
||||
from .browse import BrowserOutputObservation
|
||||
from .commands import CmdOutputObservation, IPythonRunCellObservation
|
||||
from .delegate import AgentDelegateObservation
|
||||
from .empty import NullObservation
|
||||
from .error import AgentErrorObservation
|
||||
from .files import FileReadObservation, FileWriteObservation
|
||||
from .message import AgentMessageObservation, UserMessageObservation
|
||||
from .observation import Observation
|
||||
from .recall import AgentRecallObservation
|
||||
from .run import CmdOutputObservation, IPythonRunCellObservation
|
||||
|
||||
observations = (
|
||||
CmdOutputObservation,
|
||||
@ -2,7 +2,7 @@ from dataclasses import dataclass, field
|
||||
|
||||
from opendevin.schema import ObservationType
|
||||
|
||||
from .base import Observation
|
||||
from .observation import Observation
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -2,7 +2,7 @@ from dataclasses import dataclass
|
||||
|
||||
from opendevin.schema import ObservationType
|
||||
|
||||
from .base import Observation
|
||||
from .observation import Observation
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -2,14 +2,13 @@ from dataclasses import dataclass
|
||||
|
||||
from opendevin.schema import ObservationType
|
||||
|
||||
from .base import Observation
|
||||
from .observation import Observation
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentDelegateObservation(Observation):
|
||||
"""
|
||||
This data class represents a delegate observation.
|
||||
This is used when the produced action is NOT executable.
|
||||
This data class represents the result from delegating to another agent
|
||||
"""
|
||||
|
||||
outputs: dict
|
||||
19
opendevin/events/observation/empty.py
Normal file
19
opendevin/events/observation/empty.py
Normal file
@ -0,0 +1,19 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from opendevin.schema import ObservationType
|
||||
|
||||
from .observation import Observation
|
||||
|
||||
|
||||
@dataclass
|
||||
class NullObservation(Observation):
|
||||
"""
|
||||
This data class represents a null observation.
|
||||
This is used when the produced action is NOT executable.
|
||||
"""
|
||||
|
||||
observation: str = ObservationType.NULL
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
return 'No observation'
|
||||
@ -2,7 +2,7 @@ from dataclasses import dataclass
|
||||
|
||||
from opendevin.schema import ObservationType
|
||||
|
||||
from .base import Observation
|
||||
from .observation import Observation
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -2,7 +2,7 @@ from dataclasses import dataclass
|
||||
|
||||
from opendevin.schema import ObservationType
|
||||
|
||||
from .base import Observation
|
||||
from .observation import Observation
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -2,7 +2,7 @@ from dataclasses import dataclass
|
||||
|
||||
from opendevin.schema import ObservationType
|
||||
|
||||
from .base import Observation
|
||||
from .observation import Observation
|
||||
|
||||
|
||||
@dataclass
|
||||
19
opendevin/events/observation/observation.py
Normal file
19
opendevin/events/observation/observation.py
Normal file
@ -0,0 +1,19 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from opendevin.events.event import Event
|
||||
|
||||
|
||||
@dataclass
|
||||
class Observation(Event):
|
||||
content: str
|
||||
|
||||
def to_memory(self) -> dict:
|
||||
"""Converts the observation to a dictionary."""
|
||||
extras = super().to_memory()
|
||||
content = extras.pop('content', '')
|
||||
observation = extras.pop('observation', '')
|
||||
return {
|
||||
'observation': observation,
|
||||
'content': content,
|
||||
'extras': extras,
|
||||
}
|
||||
@ -3,7 +3,7 @@ from typing import List
|
||||
|
||||
from opendevin.schema import ObservationType
|
||||
|
||||
from .base import Observation
|
||||
from .observation import Observation
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -1,52 +0,0 @@
|
||||
import copy
|
||||
from dataclasses import dataclass
|
||||
|
||||
from opendevin.schema import ObservationType
|
||||
|
||||
|
||||
@dataclass
|
||||
class Observation:
|
||||
"""
|
||||
This data class represents an observation of the environment.
|
||||
"""
|
||||
|
||||
content: str
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.content
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Converts the observation to a dictionary and adds user message."""
|
||||
memory_dict = self.to_memory()
|
||||
memory_dict['message'] = self.message
|
||||
return memory_dict
|
||||
|
||||
def to_memory(self) -> dict:
|
||||
"""Converts the observation to a dictionary."""
|
||||
extras = copy.deepcopy(self.__dict__)
|
||||
content = extras.pop('content', '')
|
||||
observation = extras.pop('observation', '')
|
||||
return {
|
||||
'observation': observation,
|
||||
'content': content,
|
||||
'extras': extras,
|
||||
}
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
"""Returns a message describing the observation."""
|
||||
return ''
|
||||
|
||||
|
||||
@dataclass
|
||||
class NullObservation(Observation):
|
||||
"""
|
||||
This data class represents a null observation.
|
||||
This is used when the produced action is NOT executable.
|
||||
"""
|
||||
|
||||
observation: str = ObservationType.NULL
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
return ''
|
||||
@ -2,15 +2,19 @@ import asyncio
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from opendevin import config
|
||||
from opendevin.action import (
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.controller import AgentController
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
NullAction,
|
||||
)
|
||||
from opendevin.agent import Agent
|
||||
from opendevin.controller import AgentController
|
||||
from opendevin.events.observation import (
|
||||
NullObservation,
|
||||
Observation,
|
||||
UserMessageObservation,
|
||||
)
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.logger import opendevin_logger as logger
|
||||
from opendevin.observation import NullObservation, Observation, UserMessageObservation
|
||||
from opendevin.schema import ActionType, ConfigType, TaskState, TaskStateAction
|
||||
from opendevin.server.session import session_manager
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
from opendevin.action import (
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
)
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
CmdOutputObservation,
|
||||
Observation,
|
||||
)
|
||||
|
||||
@ -3,25 +3,26 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
from opendevin import config
|
||||
from opendevin.action import fileop
|
||||
from opendevin.events.action import files
|
||||
from opendevin.schema import ConfigType
|
||||
|
||||
SANDBOX_PATH_PREFIX = '/workspace'
|
||||
|
||||
def test_resolve_path():
|
||||
assert fileop.resolve_path('test.txt', '/workspace') == Path(config.get(ConfigType.WORKSPACE_BASE)) / 'test.txt'
|
||||
assert fileop.resolve_path('subdir/test.txt', '/workspace') == \
|
||||
assert files.resolve_path('test.txt', '/workspace') == Path(config.get(ConfigType.WORKSPACE_BASE)) / 'test.txt'
|
||||
assert files.resolve_path('subdir/test.txt', '/workspace') == \
|
||||
Path(config.get(ConfigType.WORKSPACE_BASE)) / 'subdir' / 'test.txt'
|
||||
assert fileop.resolve_path(Path(fileop.SANDBOX_PATH_PREFIX) / 'test.txt', '/workspace') == \
|
||||
assert files.resolve_path(Path(SANDBOX_PATH_PREFIX) / 'test.txt', '/workspace') == \
|
||||
Path(config.get(ConfigType.WORKSPACE_BASE)) / 'test.txt'
|
||||
assert fileop.resolve_path(Path(fileop.SANDBOX_PATH_PREFIX) / 'subdir' / 'test.txt',
|
||||
assert files.resolve_path(Path(SANDBOX_PATH_PREFIX) / 'subdir' / 'test.txt',
|
||||
'/workspace') == Path(config.get(ConfigType.WORKSPACE_BASE)) / 'subdir' / 'test.txt'
|
||||
assert fileop.resolve_path(Path(fileop.SANDBOX_PATH_PREFIX) / 'subdir' / '..' / 'test.txt',
|
||||
assert files.resolve_path(Path(SANDBOX_PATH_PREFIX) / 'subdir' / '..' / 'test.txt',
|
||||
'/workspace') == Path(config.get(ConfigType.WORKSPACE_BASE)) / 'test.txt'
|
||||
with pytest.raises(PermissionError):
|
||||
fileop.resolve_path(Path(fileop.SANDBOX_PATH_PREFIX) / '..' / 'test.txt', '/workspace')
|
||||
files.resolve_path(Path(SANDBOX_PATH_PREFIX) / '..' / 'test.txt', '/workspace')
|
||||
with pytest.raises(PermissionError):
|
||||
fileop.resolve_path(Path('..') / 'test.txt', '/workspace')
|
||||
files.resolve_path(Path('..') / 'test.txt', '/workspace')
|
||||
with pytest.raises(PermissionError):
|
||||
fileop.resolve_path(Path('/') / 'test.txt', '/workspace')
|
||||
assert fileop.resolve_path('test.txt', '/workspace/test') == \
|
||||
files.resolve_path(Path('/') / 'test.txt', '/workspace')
|
||||
assert files.resolve_path('test.txt', '/workspace/test') == \
|
||||
Path(config.get(ConfigType.WORKSPACE_BASE)) / 'test' / 'test.txt'
|
||||
|
||||
@ -5,12 +5,12 @@ import pytest
|
||||
|
||||
from agenthub.dummy_agent.agent import DummyAgent
|
||||
from opendevin import config
|
||||
from opendevin.action.github import GitHubPushAction, GitHubSendPRAction
|
||||
from opendevin.controller.agent_controller import AgentController
|
||||
from opendevin.events.action.github import GitHubPushAction, GitHubSendPRAction
|
||||
from opendevin.events.observation.commands import CmdOutputObservation
|
||||
from opendevin.events.observation.error import AgentErrorObservation
|
||||
from opendevin.events.observation.message import AgentMessageObservation
|
||||
from opendevin.llm.llm import LLM
|
||||
from opendevin.observation.error import AgentErrorObservation
|
||||
from opendevin.observation.message import AgentMessageObservation
|
||||
from opendevin.observation.run import CmdOutputObservation
|
||||
from opendevin.schema.config import ConfigType
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from opendevin.action import (
|
||||
from opendevin.events.action import (
|
||||
Action,
|
||||
AddTaskAction,
|
||||
AgentFinishAction,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from opendevin.observation import (
|
||||
from opendevin.events.observation import (
|
||||
CmdOutputObservation,
|
||||
Observation,
|
||||
observation_from_dict,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user