mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
* add draft for skills * Implement and test agentskills functions: open_file, goto_line, scroll_down, scroll_up, create_file, search_dir, search_file, find_file * Remove new_sample.txt file * add some work from opendevin w/ fixes * Add unit tests for agentskills module * fix some issues and updated tests * add more tests for open * tweak and handle goto_line * add tests for some edge cases * add tests for scrolling * add tests for edit * add tests for search_dir * update tests to use pytest * use pytest --forked to avoid file op unit tests to interfere with each other via global var * update doc based on swe agent tool * update and add tests for find_file and search_file * move agent_skills to plugins * add agentskills as plugin and docs * add agentskill to ssh box and fix sandbox integration * remove extra returns in doc * add agentskills to initial tool for jupyter * support re-init jupyter kernel (for agentskills) after restart * fix print window's issue with indentation and add testcases * add prompt for codeact with the newest edit primitives * modify the way line number is presented (remove leading space) * change prompt to the newest display format * support tracking of costs via metrics * Update opendevin/runtime/plugins/agent_skills/README.md * Update opendevin/runtime/plugins/agent_skills/README.md * implement and add tests for py linting * remove extra text arg for incompatible subprocess ver * remove sample.txt * update test_edits integration tests * fix all integration * Update opendevin/runtime/plugins/agent_skills/README.md * Update opendevin/runtime/plugins/agent_skills/README.md * Update opendevin/runtime/plugins/agent_skills/README.md * Update agenthub/codeact_agent/prompt.py Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk> * Update agenthub/codeact_agent/prompt.py Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk> * Update agenthub/codeact_agent/prompt.py Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk> * Update opendevin/runtime/plugins/agent_skills/agentskills.py Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk> * correctly setup plugins for swebench eval * bump swe-bench version and add logging * correctly setup plugins for swebench eval * bump swe-bench version and add logging * Revert "correctly setup plugins for swebench eval" This reverts commit 2bd10556739e2af602ea85371b976390f7c48077. * bump version * remove _AGENT_SKILLS_DOCS * move flake8 to test dep * update poetry.lock * remove extra arg * reduce max iter for eval * update poetry * fix integration tests --------- Co-authored-by: OpenDevin <opendevin@opendevin.ai> Co-authored-by: Engel Nyst <enyst@users.noreply.github.com> Co-authored-by: Boxuan Li <liboxuan@connect.hku.hk>
152 lines
5.7 KiB
Python
152 lines
5.7 KiB
Python
from opendevin.core.config import config
|
|
from opendevin.events.action import (
|
|
AgentRecallAction,
|
|
BrowseInteractiveAction,
|
|
BrowseURLAction,
|
|
CmdKillAction,
|
|
CmdRunAction,
|
|
FileReadAction,
|
|
FileWriteAction,
|
|
IPythonRunCellAction,
|
|
)
|
|
from opendevin.events.observation import (
|
|
CmdOutputObservation,
|
|
ErrorObservation,
|
|
IPythonRunCellObservation,
|
|
NullObservation,
|
|
Observation,
|
|
)
|
|
from opendevin.events.stream import EventStream
|
|
from opendevin.runtime import Sandbox
|
|
from opendevin.runtime.runtime import Runtime
|
|
from opendevin.storage.local import LocalFileStore
|
|
|
|
from .browse import browse
|
|
from .files import read_file, write_file
|
|
|
|
|
|
class ServerRuntime(Runtime):
|
|
def __init__(
|
|
self,
|
|
event_stream: EventStream,
|
|
sid: str = 'default',
|
|
sandbox: Sandbox | None = None,
|
|
):
|
|
super().__init__(event_stream, sid, sandbox)
|
|
self.file_store = LocalFileStore(config.workspace_base)
|
|
|
|
async def run(self, action: CmdRunAction) -> Observation:
|
|
return self._run_command(action.command, background=action.background)
|
|
|
|
async def kill(self, action: CmdKillAction) -> Observation:
|
|
cmd = self.sandbox.kill_background(action.command_id)
|
|
return CmdOutputObservation(
|
|
content=f'Background command with id {action.command_id} has been killed.',
|
|
command_id=action.command_id,
|
|
command=cmd.command,
|
|
exit_code=0,
|
|
)
|
|
|
|
async def run_ipython(self, action: IPythonRunCellAction) -> Observation:
|
|
obs = self._run_command(
|
|
('cat > /tmp/opendevin_jupyter_temp.py <<EOL\n' f'{action.code}\n' 'EOL'),
|
|
background=False,
|
|
)
|
|
|
|
# run the code
|
|
obs = self._run_command(
|
|
('cat /tmp/opendevin_jupyter_temp.py | execute_cli'), background=False
|
|
)
|
|
output = obs.content
|
|
if 'pip install' in action.code and 'Successfully installed' in output:
|
|
print(output)
|
|
restart_kernel = 'import IPython\nIPython.Application.instance().kernel.do_shutdown(True)'
|
|
if (
|
|
'Note: you may need to restart the kernel to use updated packages.'
|
|
in output
|
|
):
|
|
obs = self._run_command(
|
|
(
|
|
'cat > /tmp/opendevin_jupyter_temp.py <<EOL\n'
|
|
f'{restart_kernel}\n'
|
|
'EOL'
|
|
),
|
|
background=False,
|
|
)
|
|
obs = self._run_command(
|
|
('cat /tmp/opendevin_jupyter_temp.py | execute_cli'),
|
|
background=False,
|
|
)
|
|
output = '[Package installed successfully]'
|
|
if "{'status': 'ok', 'restart': True}" != obs.content.strip():
|
|
print(obs.content)
|
|
output += '\n[But failed to restart the kernel to load the package]'
|
|
else:
|
|
output += '\n[Kernel restarted successfully to load the package]'
|
|
|
|
# re-init the kernel after restart
|
|
if action.kernel_init_code:
|
|
obs = self._run_command(
|
|
(
|
|
f'cat > /tmp/opendevin_jupyter_init.py <<EOL\n'
|
|
f'{action.kernel_init_code}\n'
|
|
'EOL'
|
|
),
|
|
background=False,
|
|
)
|
|
obs = self._run_command(
|
|
'cat /tmp/opendevin_jupyter_init.py | execute_cli',
|
|
background=False,
|
|
)
|
|
|
|
return IPythonRunCellObservation(content=output, code=action.code)
|
|
|
|
async def read(self, action: FileReadAction) -> Observation:
|
|
# TODO: use self.file_store
|
|
working_dir = self.sandbox.get_working_directory()
|
|
return await read_file(action.path, working_dir, action.start, action.end)
|
|
|
|
async def write(self, action: FileWriteAction) -> Observation:
|
|
# TODO: use self.file_store
|
|
working_dir = self.sandbox.get_working_directory()
|
|
return await write_file(
|
|
action.path, working_dir, action.content, action.start, action.end
|
|
)
|
|
|
|
async def browse(self, action: BrowseURLAction) -> Observation:
|
|
return await browse(action, self.browser)
|
|
|
|
async def browse_interactive(self, action: BrowseInteractiveAction) -> Observation:
|
|
return await browse(action, self.browser)
|
|
|
|
async def recall(self, action: AgentRecallAction) -> Observation:
|
|
return NullObservation('')
|
|
|
|
def _run_command(self, command: str, background=False) -> Observation:
|
|
if background:
|
|
return self._run_background(command)
|
|
else:
|
|
return self._run_immediately(command)
|
|
|
|
def _run_immediately(self, command: str) -> Observation:
|
|
try:
|
|
exit_code, output = self.sandbox.execute(command)
|
|
if 'pip install' in command and 'Successfully installed' in output:
|
|
print(output)
|
|
output = 'Package installed successfully'
|
|
return CmdOutputObservation(
|
|
command_id=-1, content=str(output), command=command, exit_code=exit_code
|
|
)
|
|
except UnicodeDecodeError:
|
|
return ErrorObservation('Command output could not be decoded as utf-8')
|
|
|
|
def _run_background(self, command: str) -> Observation:
|
|
bg_cmd = self.sandbox.execute_in_background(command)
|
|
content = f'Background command started. To stop it, send a `kill` action with command_id {bg_cmd.pid}'
|
|
return CmdOutputObservation(
|
|
content=content,
|
|
command_id=bg_cmd.pid,
|
|
command=command,
|
|
exit_code=0,
|
|
)
|