| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- import time
- from typing import List, TypedDict
- from opendevin.controller.agent import Agent
- from opendevin.controller.state.state import State
- from opendevin.events.action import (
- Action,
- AddTaskAction,
- AgentFinishAction,
- AgentRecallAction,
- AgentRejectAction,
- BrowseURLAction,
- CmdRunAction,
- FileReadAction,
- FileWriteAction,
- MessageAction,
- ModifyTaskAction,
- )
- from opendevin.events.observation import (
- AgentRecallObservation,
- CmdOutputObservation,
- FileReadObservation,
- FileWriteObservation,
- NullObservation,
- Observation,
- )
- from opendevin.llm.llm import LLM
- """
- FIXME: There are a few problems this surfaced
- * FileWrites seem to add an unintended newline at the end of the file
- * command_id is sometimes a number, sometimes a string
- * Why isn't the output of the background command split between two steps?
- * Browser not working
- """
- ActionObs = TypedDict(
- 'ActionObs', {'action': Action, 'observations': List[Observation]}
- )
- BACKGROUND_CMD = 'echo "This is in the background" && sleep .1 && echo "This too"'
- class DummyAgent(Agent):
- """
- The DummyAgent is used for e2e testing. It just sends the same set of actions deterministically,
- without making any LLM calls.
- """
- def __init__(self, llm: LLM):
- super().__init__(llm)
- self.steps: List[ActionObs] = [
- {
- 'action': AddTaskAction(parent='0', goal='check the current directory'),
- 'observations': [NullObservation('')],
- },
- {
- 'action': AddTaskAction(parent='0.0', goal='run ls'),
- 'observations': [NullObservation('')],
- },
- {
- 'action': ModifyTaskAction(id='0.0', state='in_progress'),
- 'observations': [NullObservation('')],
- },
- {
- 'action': MessageAction('Time to get started!'),
- 'observations': [NullObservation('')],
- },
- {
- 'action': CmdRunAction(command='echo "foo"'),
- 'observations': [
- CmdOutputObservation('foo', command_id=-1, command='echo "foo"')
- ],
- },
- {
- 'action': FileWriteAction(
- content='echo "Hello, World!"', path='hello.sh'
- ),
- 'observations': [FileWriteObservation('', path='hello.sh')],
- },
- {
- 'action': FileReadAction(path='hello.sh'),
- 'observations': [
- FileReadObservation('echo "Hello, World!"\n', path='hello.sh')
- ],
- },
- {
- 'action': CmdRunAction(command='bash hello.sh'),
- 'observations': [
- CmdOutputObservation(
- 'Hello, World!', command_id=-1, command='bash hello.sh'
- )
- ],
- },
- {
- 'action': CmdRunAction(command=BACKGROUND_CMD, background=True),
- 'observations': [
- CmdOutputObservation(
- 'Background command started. To stop it, send a `kill` action with id 42',
- command_id='42', # type: ignore[arg-type]
- command=BACKGROUND_CMD,
- ),
- CmdOutputObservation(
- 'This is in the background\nThis too\n',
- command_id='42', # type: ignore[arg-type]
- command=BACKGROUND_CMD,
- ),
- ],
- },
- {
- 'action': AgentRecallAction(query='who am I?'),
- 'observations': [
- AgentRecallObservation('', memories=['I am a computer.']),
- # CmdOutputObservation('This too\n', command_id='42', command=BACKGROUND_CMD),
- ],
- },
- {
- 'action': BrowseURLAction(url='https://google.com'),
- 'observations': [
- # BrowserOutputObservation('<html></html>', url='https://google.com', screenshot=""),
- ],
- },
- {
- 'action': AgentFinishAction(),
- 'observations': [],
- },
- {
- 'action': AgentRejectAction(),
- 'observations': [],
- },
- ]
- def step(self, state: State) -> Action:
- time.sleep(0.1)
- if state.iteration > 0:
- prev_step = self.steps[state.iteration - 1]
- if 'observations' in prev_step:
- expected_observations = prev_step['observations']
- hist_start = len(state.history) - len(expected_observations)
- for i in range(len(expected_observations)):
- hist_obs = state.history[hist_start + i][1].to_dict()
- expected_obs = expected_observations[i].to_dict()
- if (
- 'command_id' in hist_obs['extras']
- and hist_obs['extras']['command_id'] != -1
- ):
- del hist_obs['extras']['command_id']
- hist_obs['content'] = ''
- if (
- 'command_id' in expected_obs['extras']
- and expected_obs['extras']['command_id'] != -1
- ):
- del expected_obs['extras']['command_id']
- expected_obs['content'] = ''
- if hist_obs != expected_obs:
- print('\nactual', hist_obs)
- print('\nexpect', expected_obs)
- assert (
- hist_obs == expected_obs
- ), f'Expected observation {expected_obs}, got {hist_obs}'
- return self.steps[state.iteration]['action']
- def search_memory(self, query: str) -> List[str]:
- return ['I am a computer.']
|