diff --git a/.gitignore b/.gitignore index 2bce73cacd..9f86a2ee90 100644 --- a/.gitignore +++ b/.gitignore @@ -204,3 +204,4 @@ cache config.toml test_results* +/_test_files_tmp/ diff --git a/agenthub/SWE_agent/agent.py b/agenthub/SWE_agent/agent.py index 8fbe21ab0d..74840fb5e3 100644 --- a/agenthub/SWE_agent/agent.py +++ b/agenthub/SWE_agent/agent.py @@ -7,6 +7,7 @@ from opendevin.events.action import ( MessageAction, ) from opendevin.events.observation import Observation +from opendevin.events.serialization.event import event_to_memory from opendevin.llm.llm import LLM from .parser import parse_command @@ -36,7 +37,7 @@ class SWEAgent(Agent): def _remember(self, action: Action, observation: Observation) -> None: """Agent has a limited memory of the few steps implemented as a queue""" - memory = MEMORY_FORMAT(action.to_memory(), observation.to_memory()) + memory = MEMORY_FORMAT(event_to_memory(action), event_to_memory(observation)) self.running_memory.append(memory) def _think_act(self, messages: list[dict]) -> tuple[Action, str]: diff --git a/agenthub/dummy_agent/agent.py b/agenthub/dummy_agent/agent.py index 85abeb44f0..01c138ef1c 100644 --- a/agenthub/dummy_agent/agent.py +++ b/agenthub/dummy_agent/agent.py @@ -24,6 +24,7 @@ from opendevin.events.observation import ( NullObservation, Observation, ) +from opendevin.events.serialization.event import event_to_dict from opendevin.llm.llm import LLM """ @@ -138,8 +139,8 @@ class DummyAgent(Agent): 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() + hist_obs = event_to_dict(state.history[hist_start + i][1]) + expected_obs = event_to_dict(expected_observations[i]) if ( 'command_id' in hist_obs['extras'] and hist_obs['extras']['command_id'] != -1 diff --git a/agenthub/micro/agent.py b/agenthub/micro/agent.py index c575484c56..0957549b0c 100644 --- a/agenthub/micro/agent.py +++ b/agenthub/micro/agent.py @@ -3,7 +3,8 @@ from jinja2 import BaseLoader, Environment from opendevin.controller.agent import Agent from opendevin.controller.state.state import State from opendevin.core.utils import json -from opendevin.events.action import Action, action_from_dict +from opendevin.events.action import Action +from opendevin.events.serialization.action import action_from_dict from opendevin.llm.llm import LLM from .instructions import instructions diff --git a/agenthub/monologue_agent/agent.py b/agenthub/monologue_agent/agent.py index 73892946d1..a08b5e119c 100644 --- a/agenthub/monologue_agent/agent.py +++ b/agenthub/monologue_agent/agent.py @@ -22,6 +22,7 @@ from opendevin.events.observation import ( NullObservation, Observation, ) +from opendevin.events.serialization.event import event_to_memory from opendevin.llm.llm import LLM from opendevin.memory.condenser import MemoryCondenser from opendevin.memory.history import ShortTermHistory @@ -186,7 +187,7 @@ class MonologueAgent(Agent): observation = BrowserOutputObservation( content=thought, url='', screenshot='' ) - self._add_event(observation.to_memory()) + self._add_event(event_to_memory(observation)) previous_action = '' else: action: Action = NullAction() @@ -213,7 +214,7 @@ class MonologueAgent(Agent): previous_action = ActionType.BROWSE else: action = MessageAction(thought) - self._add_event(action.to_memory()) + self._add_event(event_to_memory(action)) def step(self, state: State) -> Action: """ @@ -229,8 +230,8 @@ class MonologueAgent(Agent): goal = state.get_current_user_intent() self._initialize(goal) for prev_action, obs in state.updated_info: - self._add_event(prev_action.to_memory()) - self._add_event(obs.to_memory()) + self._add_event(event_to_memory(prev_action)) + self._add_event(event_to_memory(obs)) state.updated_info = [] diff --git a/agenthub/monologue_agent/utils/prompts.py b/agenthub/monologue_agent/utils/prompts.py index bfec27c28e..4c9684f405 100644 --- a/agenthub/monologue_agent/utils/prompts.py +++ b/agenthub/monologue_agent/utils/prompts.py @@ -2,11 +2,11 @@ from opendevin.core.config import config from opendevin.core.utils import json from opendevin.events.action import ( Action, - action_from_dict, ) from opendevin.events.observation import ( CmdOutputObservation, ) +from opendevin.events.serialization.action import action_from_dict ACTION_PROMPT = """ You're a thoughtful robot. Your main task is this: diff --git a/agenthub/planner_agent/prompt.py b/agenthub/planner_agent/prompt.py index e5efde318a..04c32ee3bc 100644 --- a/agenthub/planner_agent/prompt.py +++ b/agenthub/planner_agent/prompt.py @@ -5,11 +5,12 @@ from opendevin.core.utils import json from opendevin.events.action import ( Action, NullAction, - action_from_dict, ) from opendevin.events.observation import ( NullObservation, ) +from opendevin.events.serialization.action import action_from_dict +from opendevin.events.serialization.event import event_to_memory HISTORY_SIZE = 10 @@ -139,10 +140,10 @@ def get_prompt(state: State) -> str: latest_action: Action = NullAction() for action, observation in sub_history: if not isinstance(action, NullAction): - history_dicts.append(action.to_memory()) + history_dicts.append(event_to_memory(action)) latest_action = action if not isinstance(observation, NullObservation): - observation_dict = observation.to_memory() + observation_dict = event_to_memory(observation) history_dicts.append(observation_dict) history_str = json.dumps(history_dicts, indent=2) current_task = state.root_task.get_current_task() @@ -152,7 +153,7 @@ def get_prompt(state: State) -> str: plan_status += "\nIf it's not achievable AND verifiable with a SINGLE action, you MUST break it down into subtasks NOW." else: plan_status = "You're not currently working on any tasks. Your next action MUST be to mark a task as in_progress." - hint = get_hint(latest_action.to_dict()['action']) + hint = get_hint(event_to_memory(latest_action).get('action', '')) logger.info('HINT:\n' + hint, extra={'msg_type': 'INFO'}) task = state.get_current_user_intent() return prompt % { diff --git a/opendevin/core/config.py b/opendevin/core/config.py index 9e626d248e..abf766761f 100644 --- a/opendevin/core/config.py +++ b/opendevin/core/config.py @@ -71,6 +71,8 @@ class AppConfig(metaclass=Singleton): llm: LLMConfig = field(default_factory=LLMConfig) agent: AgentConfig = field(default_factory=AgentConfig) runtime: str = 'server' + file_store: str = 'memory' + file_store_path: str = '/tmp/file_store' workspace_base: str = os.getcwd() workspace_mount_path: str = os.getcwd() workspace_mount_path_in_sandbox: str = '/workspace' diff --git a/opendevin/core/main.py b/opendevin/core/main.py index c0737616fb..a03876b749 100644 --- a/opendevin/core/main.py +++ b/opendevin/core/main.py @@ -76,7 +76,7 @@ async def main(task_str: str = '', exit_on_message: bool = False) -> AgentState: AgentCls: Type[Agent] = Agent.get_cls(args.agent_cls) agent = AgentCls(llm=llm) - event_stream = EventStream() + event_stream = EventStream('main') controller = AgentController( agent=agent, max_iterations=args.max_iterations, diff --git a/opendevin/events/action/__init__.py b/opendevin/events/action/__init__.py index df841d7482..9104a1e97e 100644 --- a/opendevin/events/action/__init__.py +++ b/opendevin/events/action/__init__.py @@ -1,5 +1,3 @@ -from opendevin.core.exceptions import AgentMalformedActionError - from .action import Action from .agent import ( AgentDelegateAction, @@ -16,49 +14,6 @@ from .files import FileReadAction, FileWriteAction from .message import MessageAction from .tasks import AddTaskAction, ModifyTaskAction -actions = ( - CmdKillAction, - CmdRunAction, - IPythonRunCellAction, - BrowseURLAction, - FileReadAction, - FileWriteAction, - AgentRecallAction, - AgentFinishAction, - AgentRejectAction, - AgentDelegateAction, - AddTaskAction, - ModifyTaskAction, - ChangeAgentStateAction, - MessageAction, -) - -ACTION_TYPE_TO_CLASS = {action_class.action: action_class for action_class in actions} # type: ignore[attr-defined] - - -def action_from_dict(action: dict) -> Action: - if not isinstance(action, dict): - raise AgentMalformedActionError('action must be a dictionary') - action = action.copy() - if 'action' not in action: - raise AgentMalformedActionError(f"'action' key is not found in {action=}") - if not isinstance(action['action'], str): - raise AgentMalformedActionError( - 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 AgentMalformedActionError( - f"'{action['action']=}' is not defined. Available actions: {ACTION_TYPE_TO_CLASS.keys()}" - ) - args = action.get('args', {}) - try: - decoded_action = action_class(**args) - except TypeError: - raise AgentMalformedActionError(f'action={action} has the wrong arguments') - return decoded_action - - __all__ = [ 'Action', 'NullAction', diff --git a/opendevin/events/action/action.py b/opendevin/events/action/action.py index 03fca6af2c..386e64146d 100644 --- a/opendevin/events/action/action.py +++ b/opendevin/events/action/action.py @@ -7,11 +7,3 @@ from opendevin.events.event import Event @dataclass class Action(Event): runnable: ClassVar[bool] = False - - 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} diff --git a/opendevin/events/action/commands.py b/opendevin/events/action/commands.py index 173e3758de..4148e35301 100644 --- a/opendevin/events/action/commands.py +++ b/opendevin/events/action/commands.py @@ -35,10 +35,10 @@ class CmdKillAction(Action): @property def message(self) -> str: - return f'Killing command: {self.id}' + return f'Killing command: {self.command_id}' def __str__(self) -> str: - return f'**CmdKillAction**\n{self.id}' + return f'**CmdKillAction**\n{self.command_id}' @dataclass diff --git a/opendevin/events/event.py b/opendevin/events/event.py index 3baad6f4c6..1292f9802a 100644 --- a/opendevin/events/event.py +++ b/opendevin/events/event.py @@ -1,5 +1,5 @@ import datetime -from dataclasses import asdict, dataclass +from dataclasses import dataclass from enum import Enum from typing import Optional @@ -11,16 +11,6 @@ class EventSource(str, Enum): @dataclass class Event: - def to_memory(self): - return asdict(self) - - def to_dict(self): - d = self.to_memory() - if self.source: - d['source'] = self.source - d['message'] = self.message - return d - @property def message(self) -> str: if hasattr(self, '_message'): diff --git a/opendevin/events/observation/__init__.py b/opendevin/events/observation/__init__.py index fd957b5357..34a93c60fa 100644 --- a/opendevin/events/observation/__init__.py +++ b/opendevin/events/observation/__init__.py @@ -9,40 +9,6 @@ from .observation import Observation from .recall import AgentRecallObservation from .success import SuccessObservation -observations = ( - CmdOutputObservation, - BrowserOutputObservation, - FileReadObservation, - FileWriteObservation, - AgentRecallObservation, - AgentDelegateObservation, - SuccessObservation, - ErrorObservation, - AgentStateChangedObservation, -) - -OBSERVATION_TYPE_TO_CLASS = { - observation_class.observation: observation_class # type: ignore[attr-defined] - for observation_class in observations -} - - -def observation_from_dict(observation: dict) -> Observation: - observation = observation.copy() - if 'observation' not in observation: - raise KeyError(f"'observation' key is not found in {observation=}") - observation_class = OBSERVATION_TYPE_TO_CLASS.get(observation['observation']) - if observation_class is None: - raise KeyError( - f"'{observation['observation']=}' is not defined. Available observations: {OBSERVATION_TYPE_TO_CLASS.keys()}" - ) - observation.pop('observation') - observation.pop('message', None) - content = observation.pop('content', '') - extras = observation.pop('extras', {}) - return observation_class(content=content, **extras) - - __all__ = [ 'Observation', 'NullObservation', @@ -54,4 +20,6 @@ __all__ = [ 'AgentRecallObservation', 'ErrorObservation', 'AgentStateChangedObservation', + 'AgentDelegateObservation', + 'SuccessObservation', ] diff --git a/opendevin/events/observation/browse.py b/opendevin/events/observation/browse.py index 0b1bf770fd..f945882030 100644 --- a/opendevin/events/observation/browse.py +++ b/opendevin/events/observation/browse.py @@ -1,7 +1,6 @@ from dataclasses import dataclass, field from opendevin.core.schema import ObservationType -from opendevin.events.utils import remove_fields from .observation import Observation @@ -25,29 +24,6 @@ class BrowserOutputObservation(Observation): last_browser_action: str = '' focused_element_bid: str = '' - def to_dict(self): - dictionary = super().to_dict() - # add screenshot for frontend showcase only, not for agent consumption - dictionary['screenshot'] = self.screenshot - return dictionary - - def to_memory(self) -> dict: - memory_dict = super().to_memory() - # remove some fields from the memory, as currently they are too big for LLMs - remove_fields( - memory_dict['extras'], - { - 'screenshot', - 'dom_object', - 'axtree_object', - 'open_pages_urls', - 'active_page_index', - 'last_browser_action', - 'focused_element_bid', - }, - ) - return memory_dict - @property def message(self) -> str: return 'Visited ' + self.url diff --git a/opendevin/events/observation/observation.py b/opendevin/events/observation/observation.py index 2535905639..76da5ed196 100644 --- a/opendevin/events/observation/observation.py +++ b/opendevin/events/observation/observation.py @@ -6,14 +6,3 @@ 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, - } diff --git a/opendevin/events/serialization/__init__.py b/opendevin/events/serialization/__init__.py new file mode 100644 index 0000000000..26199a2d2b --- /dev/null +++ b/opendevin/events/serialization/__init__.py @@ -0,0 +1,21 @@ +from .action import ( + action_from_dict, +) +from .event import ( + event_from_dict, + event_to_dict, + event_to_json, + event_to_memory, +) +from .observation import ( + observation_from_dict, +) + +__all__ = [ + 'action_from_dict', + 'event_from_dict', + 'event_to_dict', + 'event_to_json', + 'event_to_memory', + 'observation_from_dict', +] diff --git a/opendevin/events/serialization/action.py b/opendevin/events/serialization/action.py new file mode 100644 index 0000000000..fcc5c9df5c --- /dev/null +++ b/opendevin/events/serialization/action.py @@ -0,0 +1,60 @@ +from opendevin.core.exceptions import AgentMalformedActionError +from opendevin.events.action.action import Action +from opendevin.events.action.agent import ( + AgentDelegateAction, + AgentFinishAction, + AgentRecallAction, + AgentRejectAction, + ChangeAgentStateAction, +) +from opendevin.events.action.browse import BrowseURLAction +from opendevin.events.action.commands import ( + CmdKillAction, + CmdRunAction, + IPythonRunCellAction, +) +from opendevin.events.action.files import FileReadAction, FileWriteAction +from opendevin.events.action.message import MessageAction +from opendevin.events.action.tasks import AddTaskAction, ModifyTaskAction + +actions = ( + CmdKillAction, + CmdRunAction, + IPythonRunCellAction, + BrowseURLAction, + FileReadAction, + FileWriteAction, + AgentRecallAction, + AgentFinishAction, + AgentRejectAction, + AgentDelegateAction, + AddTaskAction, + ModifyTaskAction, + ChangeAgentStateAction, + MessageAction, +) + +ACTION_TYPE_TO_CLASS = {action_class.action: action_class for action_class in actions} # type: ignore[attr-defined] + + +def action_from_dict(action: dict) -> Action: + if not isinstance(action, dict): + raise AgentMalformedActionError('action must be a dictionary') + action = action.copy() + if 'action' not in action: + raise AgentMalformedActionError(f"'action' key is not found in {action=}") + if not isinstance(action['action'], str): + raise AgentMalformedActionError( + 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 AgentMalformedActionError( + f"'{action['action']=}' is not defined. Available actions: {ACTION_TYPE_TO_CLASS.keys()}" + ) + args = action.get('args', {}) + try: + decoded_action = action_class(**args) + except TypeError: + raise AgentMalformedActionError(f'action={action} has the wrong arguments') + return decoded_action diff --git a/opendevin/events/serialization/event.py b/opendevin/events/serialization/event.py new file mode 100644 index 0000000000..9d52d0164b --- /dev/null +++ b/opendevin/events/serialization/event.py @@ -0,0 +1,77 @@ +import json +from dataclasses import asdict +from datetime import datetime +from typing import TYPE_CHECKING + +from .action import action_from_dict +from .observation import observation_from_dict +from .utils import remove_fields + +if TYPE_CHECKING: + from opendevin.events.event import Event + +# TODO: move `content` into `extras` +TOP_KEYS = ['id', 'timestamp', 'source', 'message', 'cause', 'action', 'observation'] + +DELETE_FROM_MEMORY_EXTRAS = { + 'screenshot', + 'dom_object', + 'axtree_object', + 'open_pages_urls', + 'active_page_index', + 'last_browser_action', + 'focused_element_bid', +} + + +def json_serial(obj): + if isinstance(obj, datetime): + return obj.isoformat() + if obj is None: + return None + return str(obj) + + +def event_from_dict(data) -> 'Event': + if 'action' in data: + return action_from_dict(data) + elif 'observation' in data: + return observation_from_dict(data) + else: + raise ValueError('Unknown event type: ' + data) + + +def event_to_dict(event: 'Event') -> dict: + props = asdict(event) + d = {} + for key in TOP_KEYS: + if hasattr(event, key) and getattr(event, key) is not None: + d[key] = getattr(event, key) + elif hasattr(event, f'_{key}') and getattr(event, f'_{key}') is not None: + d[key] = getattr(event, f'_{key}') + if key == 'id' and d.get('id') == -1: + d.pop('id', None) + props.pop(key, None) + if 'action' in d: + d['args'] = props + elif 'observation' in d: + d['content'] = props.pop('content', '') + d['extras'] = props + else: + raise ValueError('Event must be either action or observation') + return d + + +def event_to_memory(event: 'Event') -> dict: + d = event_to_dict(event) + d.pop('id', None) + d.pop('cause', None) + d.pop('timestamp', None) + d.pop('message', None) + if 'extras' in d: + remove_fields(d['extras'], DELETE_FROM_MEMORY_EXTRAS) + return d + + +def event_to_json(event: 'Event'): + return json.dumps(event_to_dict(event), default=json_serial) diff --git a/opendevin/events/serialization/observation.py b/opendevin/events/serialization/observation.py new file mode 100644 index 0000000000..80e3f7d09a --- /dev/null +++ b/opendevin/events/serialization/observation.py @@ -0,0 +1,46 @@ +from opendevin.events.observation.agent import AgentStateChangedObservation +from opendevin.events.observation.browse import BrowserOutputObservation +from opendevin.events.observation.commands import ( + CmdOutputObservation, +) +from opendevin.events.observation.delegate import AgentDelegateObservation +from opendevin.events.observation.empty import NullObservation +from opendevin.events.observation.error import ErrorObservation +from opendevin.events.observation.files import FileReadObservation, FileWriteObservation +from opendevin.events.observation.observation import Observation +from opendevin.events.observation.recall import AgentRecallObservation +from opendevin.events.observation.success import SuccessObservation + +observations = ( + NullObservation, + CmdOutputObservation, + BrowserOutputObservation, + FileReadObservation, + FileWriteObservation, + AgentRecallObservation, + AgentDelegateObservation, + SuccessObservation, + ErrorObservation, + AgentStateChangedObservation, +) + +OBSERVATION_TYPE_TO_CLASS = { + observation_class.observation: observation_class # type: ignore[attr-defined] + for observation_class in observations +} + + +def observation_from_dict(observation: dict) -> Observation: + observation = observation.copy() + if 'observation' not in observation: + raise KeyError(f"'observation' key is not found in {observation=}") + observation_class = OBSERVATION_TYPE_TO_CLASS.get(observation['observation']) + if observation_class is None: + raise KeyError( + f"'{observation['observation']=}' is not defined. Available observations: {OBSERVATION_TYPE_TO_CLASS.keys()}" + ) + observation.pop('observation') + observation.pop('message', None) + content = observation.pop('content', '') + extras = observation.pop('extras', {}) + return observation_class(content=content, **extras) diff --git a/opendevin/events/utils.py b/opendevin/events/serialization/utils.py similarity index 100% rename from opendevin/events/utils.py rename to opendevin/events/serialization/utils.py diff --git a/opendevin/events/stream.py b/opendevin/events/stream.py index 3679c335af..f1df4bcc22 100644 --- a/opendevin/events/stream.py +++ b/opendevin/events/stream.py @@ -1,9 +1,12 @@ import asyncio +import json from datetime import datetime from enum import Enum from typing import Callable from opendevin.core.logger import opendevin_logger as logger +from opendevin.events.serialization.event import event_from_dict, event_to_json +from opendevin.storage import FileStore, get_file_store from .event import Event, EventSource @@ -13,14 +16,37 @@ class EventStreamSubscriber(str, Enum): SERVER = 'server' RUNTIME = 'runtime' MAIN = 'main' + TEST = 'test' class EventStream: - def __init__(self): - self._subscribers: dict[str, Callable] = {} - self._events: list[Event] = [] + sid: str + _subscribers: dict[str, Callable] + _events: list[Event] + _lock: asyncio.Lock + _file_store: FileStore + + def __init__(self, sid: str): + self.sid = sid + self._file_store = get_file_store() + self._subscribers = {} + self._events = [] self._lock = asyncio.Lock() + def _get_filename_for_event(self, event: Event): + # TODO: change to .id once that prop is in + return f'sessions/{self.sid}/events/{event._id}.json' # type: ignore [attr-defined] + + async def _rehydrate(self): + async with self._lock: + self._events = [] + events = self._file_store.list(f'sessions/{self.sid}/events') + for event_str in events: + content = self._file_store.read(event_str) + data = json.loads(content) + event = event_from_dict(data) + self._events.append(event) + def subscribe(self, id: EventStreamSubscriber, callback: Callable): if id in self._subscribers: raise ValueError('Subscriber already exists: ' + id) @@ -36,9 +62,12 @@ class EventStream: # TODO: make this not async async def add_event(self, event: Event, source: EventSource): async with self._lock: - event._id = len(self._events) # type: ignore[attr-defined] - event._timestamp = datetime.now() # type: ignore[attr-defined] - event._source = source # type: ignore[attr-defined] + event._id = len(self._events) # type: ignore [attr-defined] + event._timestamp = datetime.now() # type: ignore [attr-defined] + event._source = source # type: ignore [attr-defined] + self._file_store.write( + self._get_filename_for_event(event), event_to_json(event) + ) self._events.append(event) for key, fn in self._subscribers.items(): await fn(event) diff --git a/opendevin/runtime/runtime.py b/opendevin/runtime/runtime.py index 0885874cea..36fb9e7833 100644 --- a/opendevin/runtime/runtime.py +++ b/opendevin/runtime/runtime.py @@ -3,7 +3,6 @@ from abc import abstractmethod from opendevin.core.config import config from opendevin.events.action import ( - ACTION_TYPE_TO_CLASS, Action, AgentRecallAction, BrowseURLAction, @@ -20,6 +19,7 @@ from opendevin.events.observation import ( NullObservation, Observation, ) +from opendevin.events.serialization.action import ACTION_TYPE_TO_CLASS from opendevin.events.stream import EventSource, EventStream, EventStreamSubscriber from opendevin.runtime import ( DockerExecBox, diff --git a/opendevin/runtime/server/runtime.py b/opendevin/runtime/server/runtime.py index 74f94af584..d523e0ff38 100644 --- a/opendevin/runtime/server/runtime.py +++ b/opendevin/runtime/server/runtime.py @@ -28,7 +28,7 @@ class ServerRuntime(Runtime): 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.id, + command_id=action.command_id, command=cmd.command, exit_code=0, ) diff --git a/opendevin/server/agent/agent.py b/opendevin/server/agent/agent.py index ace4f6b0e4..43bd9f40e7 100644 --- a/opendevin/server/agent/agent.py +++ b/opendevin/server/agent/agent.py @@ -10,12 +10,13 @@ from opendevin.core.schema import ActionType, AgentState, ConfigType from opendevin.events.action import ( ChangeAgentStateAction, NullAction, - action_from_dict, ) from opendevin.events.event import Event from opendevin.events.observation import ( NullObservation, ) +from opendevin.events.serialization.action import action_from_dict +from opendevin.events.serialization.event import event_to_dict from opendevin.events.stream import EventSource, EventStream, EventStreamSubscriber from opendevin.llm.llm import LLM from opendevin.runtime import DockerSSHBox @@ -40,7 +41,7 @@ class AgentUnit: def __init__(self, sid): """Initializes a new instance of the Session class.""" self.sid = sid - self.event_stream = EventStream() + self.event_stream = EventStream(sid) self.event_stream.subscribe(EventStreamSubscriber.SERVER, self.on_event) if config.runtime == 'server': logger.info('Using server runtime') @@ -141,11 +142,14 @@ class AgentUnit: Args: event: The agent event (Observation or Action). """ + if isinstance(event, NullAction): + return + if isinstance(event, NullObservation): + return if event.source == 'agent' and not isinstance( event, (NullAction, NullObservation) ): - await self.send(event.to_dict()) - return + await self.send(event_to_dict(event)) async def close(self): if self.controller is not None: diff --git a/opendevin/storage/__init__.py b/opendevin/storage/__init__.py new file mode 100644 index 0000000000..6ac583fd48 --- /dev/null +++ b/opendevin/storage/__init__.py @@ -0,0 +1,21 @@ +from opendevin.core.config import config + +from .files import FileStore +from .local import LocalFileStore +from .memory import InMemoryFileStore +from .s3 import S3FileStore + + +def _get_file_store() -> FileStore: + if config.file_store == 'local': + return LocalFileStore(config.file_store_path) + elif config.file_store == 's3': + return S3FileStore() + return InMemoryFileStore() + + +singleton = _get_file_store() + + +def get_file_store() -> FileStore: + return singleton diff --git a/opendevin/storage/files.py b/opendevin/storage/files.py new file mode 100644 index 0000000000..5a210eca80 --- /dev/null +++ b/opendevin/storage/files.py @@ -0,0 +1,19 @@ +from abc import abstractmethod + + +class FileStore: + @abstractmethod + def write(self, path: str, contents: str) -> None: + pass + + @abstractmethod + def read(self, path: str) -> str: + pass + + @abstractmethod + def list(self, path: str) -> list[str]: + pass + + @abstractmethod + def delete(self, path: str) -> None: + pass diff --git a/opendevin/storage/local.py b/opendevin/storage/local.py new file mode 100644 index 0000000000..8cc530599b --- /dev/null +++ b/opendevin/storage/local.py @@ -0,0 +1,35 @@ +import os + +from .files import FileStore + + +class LocalFileStore(FileStore): + root: str + + def __init__(self, root: str): + self.root = root + os.makedirs(self.root, exist_ok=True) + + def get_full_path(self, path: str) -> str: + if path.startswith('/'): + path = path[1:] + return os.path.join(self.root, path) + + def write(self, path: str, contents: str) -> None: + full_path = self.get_full_path(path) + os.makedirs(os.path.dirname(full_path), exist_ok=True) + with open(full_path, 'w') as f: + f.write(contents) + + def read(self, path: str) -> str: + full_path = self.get_full_path(path) + with open(full_path, 'r') as f: + return f.read() + + def list(self, path: str) -> list[str]: + full_path = self.get_full_path(path) + return [os.path.join(path, f) for f in os.listdir(full_path)] + + def delete(self, path: str) -> None: + full_path = self.get_full_path(path) + os.remove(full_path) diff --git a/opendevin/storage/memory.py b/opendevin/storage/memory.py new file mode 100644 index 0000000000..45d4ce100f --- /dev/null +++ b/opendevin/storage/memory.py @@ -0,0 +1,38 @@ +import os + +from .files import FileStore + + +class InMemoryFileStore(FileStore): + files: dict[str, str] + + def __init__(self): + self.files = {} + + def write(self, path: str, contents: str) -> None: + self.files[path] = contents + + def read(self, path: str) -> str: + if path not in self.files: + raise FileNotFoundError(path) + return self.files[path] + + def list(self, path: str) -> list[str]: + files = [] + for file in self.files: + if not file.startswith(path): + continue + suffix = file.removeprefix(path) + parts = suffix.split('/') + if parts[0] == '': + parts.pop(0) + if len(parts) == 1: + files.append(file) + else: + dir_path = os.path.join(path, parts[0]) + if dir_path not in files: + files.append(dir_path) + return files + + def delete(self, path: str) -> None: + del self.files[path] diff --git a/opendevin/storage/s3.py b/opendevin/storage/s3.py new file mode 100644 index 0000000000..4f6d3c4f5f --- /dev/null +++ b/opendevin/storage/s3.py @@ -0,0 +1,27 @@ +import os + +from minio import Minio + +from .files import FileStore + +AWS_S3_ENDPOINT = 's3.amazonaws.com' + + +class S3FileStore(FileStore): + def __init__(self, endpoint: str = AWS_S3_ENDPOINT) -> None: + access_key = os.getenv('AWS_ACCESS_KEY_ID') + secret_key = os.getenv('AWS_SECRET_ACCESS_KEY') + self.bucket = os.getenv('AWS_S3_BUCKET') + self.client = Minio(endpoint, access_key, secret_key) + + def write(self, path: str, contents: str) -> None: + self.client.put_object(self.bucket, path, contents) + + def read(self, path: str) -> str: + return self.client.get_object(self.bucket, path).data.decode('utf-8') + + def list(self, path: str) -> list[str]: + return [obj.object_name for obj in self.client.list_objects(self.bucket, path)] + + def delete(self, path: str) -> None: + self.client.remove_object(self.bucket, path) diff --git a/poetry.lock b/poetry.lock index 466dde2a1c..f4e0005767 100644 --- a/poetry.lock +++ b/poetry.lock @@ -163,6 +163,63 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (>=0.23)"] +[[package]] +name = "argon2-cffi" +version = "23.1.0" +description = "Argon2 for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, + {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, +] + +[package.dependencies] +argon2-cffi-bindings = "*" + +[package.extras] +dev = ["argon2-cffi[tests,typing]", "tox (>4)"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] +tests = ["hypothesis", "pytest"] +typing = ["mypy"] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +description = "Low-level CFFI bindings for Argon2" +optional = false +python-versions = ">=3.6" +files = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] + +[package.dependencies] +cffi = ">=1.0.1" + +[package.extras] +dev = ["cogapp", "pre-commit", "pytest", "wheel"] +tests = ["pytest"] + [[package]] name = "asgiref" version = "3.8.1" @@ -3146,6 +3203,24 @@ files = [ {file = "minijinja-2.0.1.tar.gz", hash = "sha256:e774beffebfb8a1ad17e638ef70917cf5e94593f79acb8a8fff7d983169f3a4e"}, ] +[[package]] +name = "minio" +version = "7.2.7" +description = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage" +optional = false +python-versions = "*" +files = [ + {file = "minio-7.2.7-py3-none-any.whl", hash = "sha256:59d1f255d852fe7104018db75b3bebbd987e538690e680f7c5de835e422de837"}, + {file = "minio-7.2.7.tar.gz", hash = "sha256:473d5d53d79f340f3cd632054d0c82d2f93177ce1af2eac34a235bea55708d98"}, +] + +[package.dependencies] +argon2-cffi = "*" +certifi = "*" +pycryptodome = "*" +typing-extensions = "*" +urllib3 = "*" + [[package]] name = "mmh3" version = "4.1.0" @@ -4484,6 +4559,47 @@ files = [ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] +[[package]] +name = "pycryptodome" +version = "3.20.0" +description = "Cryptographic library for Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, + {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, +] + [[package]] name = "pydantic" version = "2.7.1" @@ -6817,4 +6933,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "bb90115473396471c0bad6dc4152100683e3057e2b1189527de7a82c4f393341" +content-hash = "b531f9f1630faffd0f97de2f24085694bc1cb6d0eb51b37e3ab78de0e858f2fe" diff --git a/pyproject.toml b/pyproject.toml index bf1db2bf4b..2e4f87cddf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,9 @@ pexpect = "*" jinja2 = "^3.1.3" python-multipart = "*" boto3 = "*" +minio = "^7.2.7" gevent = "^24.2.1" +pyarrow = "16.0.0" # transitive dependency, pinned here to avoid conflicts [tool.poetry.group.llama-index.dependencies] llama-index = "*" diff --git a/tests/integration/mock/MonologueAgent/test_edits/prompt_001.log b/tests/integration/mock/MonologueAgent/test_edits/prompt_001.log index d283224b02..9f18e9e880 100644 --- a/tests/integration/mock/MonologueAgent/test_edits/prompt_001.log +++ b/tests/integration/mock/MonologueAgent/test_edits/prompt_001.log @@ -320,6 +320,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "user", "action": "message", "args": { "content": "Fix typos in bad.txt. Do not ask me for confirmation at any point.", diff --git a/tests/integration/mock/MonologueAgent/test_edits/prompt_002.log b/tests/integration/mock/MonologueAgent/test_edits/prompt_002.log index da98f7ab93..229a56f329 100644 --- a/tests/integration/mock/MonologueAgent/test_edits/prompt_002.log +++ b/tests/integration/mock/MonologueAgent/test_edits/prompt_002.log @@ -320,6 +320,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "user", "action": "message", "args": { "content": "Fix typos in bad.txt. Do not ask me for confirmation at any point.", @@ -332,6 +333,7 @@ This is your internal monologue, in JSON format: "extras": {} }, { + "source": "agent", "action": "read", "args": { "path": "bad.txt", @@ -341,6 +343,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "agent", "observation": "read", "content": "This is a stupid typoo.\nReally?\nNo mor typos!\nEnjoy!\n", "extras": { diff --git a/tests/integration/mock/MonologueAgent/test_edits/prompt_003.log b/tests/integration/mock/MonologueAgent/test_edits/prompt_003.log index 4d219d48c6..697ee646c0 100644 --- a/tests/integration/mock/MonologueAgent/test_edits/prompt_003.log +++ b/tests/integration/mock/MonologueAgent/test_edits/prompt_003.log @@ -320,6 +320,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "user", "action": "message", "args": { "content": "Fix typos in bad.txt. Do not ask me for confirmation at any point.", @@ -332,6 +333,7 @@ This is your internal monologue, in JSON format: "extras": {} }, { + "source": "agent", "action": "read", "args": { "path": "bad.txt", @@ -341,6 +343,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "agent", "observation": "read", "content": "This is a stupid typoo.\nReally?\nNo mor typos!\nEnjoy!\n", "extras": { @@ -348,6 +351,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "agent", "action": "write", "args": { "path": "bad.txt", @@ -358,6 +362,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "agent", "observation": "write", "content": "", "extras": { diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_001.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_001.log index 0cc7821f95..22aaa03a2d 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_001.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_001.log @@ -320,6 +320,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "user", "action": "message", "args": { "content": "Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point.", diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_002.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_002.log index d7606e0644..ee6a3d0adf 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_002.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_002.log @@ -320,6 +320,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "user", "action": "message", "args": { "content": "Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point.", @@ -332,6 +333,7 @@ This is your internal monologue, in JSON format: "extras": {} }, { + "source": "agent", "action": "write", "args": { "path": "hello.sh", @@ -342,6 +344,7 @@ This is your internal monologue, in JSON format: } }, { + "source": "agent", "observation": "write", "content": "", "extras": { diff --git a/tests/integration/mock/PlannerAgent/test_edits/prompt_001.log b/tests/integration/mock/PlannerAgent/test_edits/prompt_001.log index d13b54c32d..b5ceac4c97 100644 --- a/tests/integration/mock/PlannerAgent/test_edits/prompt_001.log +++ b/tests/integration/mock/PlannerAgent/test_edits/prompt_001.log @@ -53,6 +53,7 @@ ten actions--more happened before that. [ { + "source": "user", "action": "message", "args": { "content": "Fix typos in bad.txt. Do not ask me for confirmation at any point.", diff --git a/tests/integration/mock/PlannerAgent/test_edits/prompt_002.log b/tests/integration/mock/PlannerAgent/test_edits/prompt_002.log index 94f233336c..3472f1c9d1 100644 --- a/tests/integration/mock/PlannerAgent/test_edits/prompt_002.log +++ b/tests/integration/mock/PlannerAgent/test_edits/prompt_002.log @@ -53,6 +53,7 @@ ten actions--more happened before that. [ { + "source": "user", "action": "message", "args": { "content": "Fix typos in bad.txt. Do not ask me for confirmation at any point.", @@ -60,6 +61,7 @@ ten actions--more happened before that. } }, { + "source": "agent", "action": "read", "args": { "path": "bad.txt", @@ -69,6 +71,7 @@ ten actions--more happened before that. } }, { + "source": "agent", "observation": "read", "content": "This is a stupid typoo.\nReally?\nNo mor typos!\nEnjoy!\n", "extras": { diff --git a/tests/integration/mock/PlannerAgent/test_edits/prompt_003.log b/tests/integration/mock/PlannerAgent/test_edits/prompt_003.log index db4a083ae4..420e5a8e21 100644 --- a/tests/integration/mock/PlannerAgent/test_edits/prompt_003.log +++ b/tests/integration/mock/PlannerAgent/test_edits/prompt_003.log @@ -53,6 +53,7 @@ ten actions--more happened before that. [ { + "source": "user", "action": "message", "args": { "content": "Fix typos in bad.txt. Do not ask me for confirmation at any point.", @@ -60,6 +61,7 @@ ten actions--more happened before that. } }, { + "source": "agent", "action": "read", "args": { "path": "bad.txt", @@ -69,6 +71,7 @@ ten actions--more happened before that. } }, { + "source": "agent", "observation": "read", "content": "This is a stupid typoo.\nReally?\nNo mor typos!\nEnjoy!\n", "extras": { @@ -76,20 +79,11 @@ ten actions--more happened before that. } }, { - "action": "write", + "source": "agent", + "action": "message", "args": { - "path": "bad.txt", - "content": "This is a stupid typo.\nReally?\nNo more typos!\nEnjoy!\n", - "start": 0, - "end": -1, - "thought": "" - } - }, - { - "observation": "write", - "content": "", - "extras": { - "path": "bad.txt" + "content": "I have read the content of bad.txt and identified the typos that need to be fixed. I will now proceed to fix the typos in the file.", + "wait_for_response": false } } ] @@ -133,4 +127,4 @@ actions are all `message` actions, you should consider taking a different action What is your next thought or action? Again, you must reply with JSON, and only with JSON. -You just changed a file. You should think about how it affects your plan. +Look at your last thought in the history above. What does it suggest? Don't think anymore--take action. diff --git a/tests/integration/mock/PlannerAgent/test_edits/prompt_004.log b/tests/integration/mock/PlannerAgent/test_edits/prompt_004.log new file mode 100644 index 0000000000..274b9e2682 --- /dev/null +++ b/tests/integration/mock/PlannerAgent/test_edits/prompt_004.log @@ -0,0 +1,149 @@ + + +---------- + + +# Task +You're a diligent software engineer AI. You can't see, draw, or interact with a +browser, but you can read and write files, and you can run commands, and you can think. + +You've been given the following task: + +Fix typos in bad.txt. Do not ask me for confirmation at any point. + +## Plan +As you complete this task, you're building a plan and keeping +track of your progress. Here's a JSON representation of your plan: + +{ + "id": "", + "goal": "", + "state": "open", + "subtasks": [] +} + + +You're not currently working on any tasks. Your next action MUST be to mark a task as in_progress. + +You're responsible for managing this plan and the status of tasks in +it, by using the `add_task` and `modify_task` actions described below. + +If the History below contradicts the state of any of these tasks, you +MUST modify the task using the `modify_task` action described below. + +Be sure NOT to duplicate any tasks. Do NOT use the `add_task` action for +a task that's already represented. Every task must be represented only once. + +Tasks that are sequential MUST be siblings. They must be added in order +to their parent task. + +If you mark a task as 'completed', 'verified', or 'abandoned', +all non-abandoned subtasks will be marked the same way. +So before closing a task this way, you MUST not only be sure that it has +been completed successfully--you must ALSO be sure that all its subtasks +are ready to be marked the same way. + +If, and only if, ALL tasks have already been marked verified, +you MUST respond with the `finish` action. + +## History +Here is a recent history of actions you've taken in service of this plan, +as well as observations you've made. This only includes the MOST RECENT +ten actions--more happened before that. + +[ + { + "source": "user", + "action": "message", + "args": { + "content": "Fix typos in bad.txt. Do not ask me for confirmation at any point.", + "wait_for_response": false + } + }, + { + "source": "agent", + "action": "read", + "args": { + "path": "bad.txt", + "start": 0, + "end": -1, + "thought": "" + } + }, + { + "source": "agent", + "observation": "read", + "content": "This is a stupid typoo.\nReally?\nNo mor typos!\nEnjoy!\n", + "extras": { + "path": "bad.txt" + } + }, + { + "source": "agent", + "action": "message", + "args": { + "content": "I have read the content of bad.txt and identified the typos that need to be fixed. I will now proceed to fix the typos in the file.", + "wait_for_response": false + } + }, + { + "source": "agent", + "action": "write", + "args": { + "path": "bad.txt", + "content": "This is a stupid typo.\nReally?\nNo more typos!\nEnjoy!\n", + "start": 0, + "end": -1, + "thought": "" + } + }, + { + "source": "agent", + "observation": "write", + "content": "", + "extras": { + "path": "bad.txt" + } + } +] + + +Your most recent action is at the bottom of that history. + +## Action +What is your next thought or action? Your response must be in JSON format. + +It must be an object, and it must contain two fields: +* `action`, which is one of the actions below +* `args`, which is a map of key-value pairs, specifying the arguments for that action + +* `read` - reads the content of a file. Arguments: + * `path` - the path of the file to read +* `write` - writes the content to a file. Arguments: + * `path` - the path of the file to write + * `content` - the content to write to the file +* `run` - runs a command on the command line in a Linux shell. Arguments: + * `command` - the command to run + * `background` - if true, run the command in the background, so that other commands can be run concurrently. Useful for e.g. starting a server. You won't be able to see the logs. You don't need to end the command with `&`, just set this to true. +* `kill` - kills a background command + * `command_id` - the ID of the background command to kill +* `browse` - opens a web page. Arguments: + * `url` - the URL to open +* `message` - make a plan, set a goal, or record your thoughts. Arguments: + * `content` - the message to record +* `add_task` - add a task to your plan. Arguments: + * `parent` - the ID of the parent task (leave empty if it should go at the top level) + * `goal` - the goal of the task + * `subtasks` - a list of subtasks, each of which is a map with a `goal` key. +* `modify_task` - close a task. Arguments: + * `task_id` - the ID of the task to close + * `state` - set to 'in_progress' to start the task, 'completed' to finish it, 'verified' to assert that it was successful, 'abandoned' to give up on it permanently, or `open` to stop working on it for now. +* `finish` - if ALL of your tasks and subtasks have been verified or abandoned, and you're absolutely certain that you've completed your task and have tested your work, use the finish action to stop working. + +You MUST take time to think in between read, write, run, browse, and recall actions--do this with the `message` action. +You should never act twice in a row without thinking. But if your last several +actions are all `message` actions, you should consider taking a different action. + +What is your next thought or action? Again, you must reply with JSON, and only with JSON. + +You just changed a file. You should think about how it affects your plan. diff --git a/tests/integration/mock/PlannerAgent/test_edits/response_002.log b/tests/integration/mock/PlannerAgent/test_edits/response_002.log index 64308f91f8..abd18c89d1 100644 --- a/tests/integration/mock/PlannerAgent/test_edits/response_002.log +++ b/tests/integration/mock/PlannerAgent/test_edits/response_002.log @@ -1,7 +1,6 @@ { - "action": "write", + "action": "message", "args": { - "path": "bad.txt", - "content": "This is a stupid typo.\nReally?\nNo more typos!\nEnjoy!\n" + "content": "I have read the content of bad.txt and identified the typos that need to be fixed. I will now proceed to fix the typos in the file." } } diff --git a/tests/integration/mock/PlannerAgent/test_edits/response_003.log b/tests/integration/mock/PlannerAgent/test_edits/response_003.log index 4c19964bc6..64308f91f8 100644 --- a/tests/integration/mock/PlannerAgent/test_edits/response_003.log +++ b/tests/integration/mock/PlannerAgent/test_edits/response_003.log @@ -1,3 +1,7 @@ { - "action": "finish" + "action": "write", + "args": { + "path": "bad.txt", + "content": "This is a stupid typo.\nReally?\nNo more typos!\nEnjoy!\n" + } } diff --git a/tests/integration/mock/PlannerAgent/test_edits/response_004.log b/tests/integration/mock/PlannerAgent/test_edits/response_004.log new file mode 100644 index 0000000000..c6819f9911 --- /dev/null +++ b/tests/integration/mock/PlannerAgent/test_edits/response_004.log @@ -0,0 +1,4 @@ +{ + "action": "finish", + "args": {} +} diff --git a/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_001.log b/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_001.log index 5121fd5d8e..3406c3406b 100644 --- a/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_001.log +++ b/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_001.log @@ -53,6 +53,7 @@ ten actions--more happened before that. [ { + "source": "user", "action": "message", "args": { "content": "Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point.", diff --git a/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_002.log b/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_002.log index 52a5882eaf..c4da9c5446 100644 --- a/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_002.log +++ b/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_002.log @@ -53,6 +53,7 @@ ten actions--more happened before that. [ { + "source": "user", "action": "message", "args": { "content": "Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point.", @@ -60,6 +61,7 @@ ten actions--more happened before that. } }, { + "source": "agent", "action": "write", "args": { "path": "hello.sh", @@ -70,6 +72,7 @@ ten actions--more happened before that. } }, { + "source": "agent", "observation": "write", "content": "", "extras": { diff --git a/tests/integration/mock/PlannerAgent/test_write_simple_script/response_002.log b/tests/integration/mock/PlannerAgent/test_write_simple_script/response_002.log index 4c19964bc6..c6819f9911 100644 --- a/tests/integration/mock/PlannerAgent/test_write_simple_script/response_002.log +++ b/tests/integration/mock/PlannerAgent/test_write_simple_script/response_002.log @@ -1,3 +1,4 @@ { - "action": "finish" + "action": "finish", + "args": {} } diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_001.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_001.log index 3e700d6259..ff84779de3 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_001.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_001.log @@ -61,6 +61,7 @@ These are your past 4 actions: Memory 0: Previous Action: +source: EventSource.USER action: message args: wait_for_response: False diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_002.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_002.log index f218394672..399165c0d4 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_002.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_002.log @@ -61,6 +61,7 @@ These are your past 4 actions: Memory 0: Previous Action: +source: EventSource.USER action: message args: wait_for_response: False @@ -72,17 +73,19 @@ extras: Memory 1: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - To begin solving the task, I need to create a new shell script named 'hello.sh'. This script should contain a simple command to print 'hello'. I will use the `write` command to create this file and insert the necessary bash script code. + I need to create a shell script named 'hello.sh' that prints 'hello' without asking for confirmation. I will need to ensure that the script is executable. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_003.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_003.log index 05eb4ee596..c0b804a037 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_003.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_003.log @@ -61,6 +61,7 @@ These are your past 4 actions: Memory 0: Previous Action: +source: EventSource.USER action: message args: wait_for_response: False @@ -72,17 +73,19 @@ extras: Memory 1: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - To begin solving the task, I need to create a new shell script named 'hello.sh'. This script should contain a simple command to print 'hello'. I will use the `write` command to create this file and insert the necessary bash script code. + I need to create a shell script named 'hello.sh' that prints 'hello' without asking for confirmation. I will need to ensure that the script is executable. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -90,17 +93,19 @@ extras: Memory 2: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I have created the file 'hello.sh' but I have not yet written any content into it. The task requires me to write a shell script that prints 'hello'. I need to add the appropriate bash command to this file to fulfill the requirement. The command to print in bash is `echo`. I will write this command into 'hello.sh'. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_004.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_004.log index 1fb2e92a2f..02d9e2e8a3 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_004.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_004.log @@ -61,6 +61,7 @@ These are your past 4 actions: Memory 0: Previous Action: +source: EventSource.USER action: message args: wait_for_response: False @@ -72,17 +73,19 @@ extras: Memory 1: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - To begin solving the task, I need to create a new shell script named 'hello.sh'. This script should contain a simple command to print 'hello'. I will use the `write` command to create this file and insert the necessary bash script code. + I need to create a shell script named 'hello.sh' that prints 'hello' without asking for confirmation. I will need to ensure that the script is executable. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -90,17 +93,19 @@ extras: Memory 2: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I have created the file 'hello.sh' but I have not yet written any content into it. The task requires me to write a shell script that prints 'hello'. I need to add the appropriate bash command to this file to fulfill the requirement. The command to print in bash is `echo`. I will write this command into 'hello.sh'. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -108,17 +113,19 @@ extras: Memory 3: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - Based on the previous actions, it appears that the file 'hello.sh' has been created but no content has been written into it yet. The task requires a shell script that prints 'hello'. I need to write the appropriate bash command into 'hello.sh' to fulfill this requirement. The command to print in bash is `echo "hello"`. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_005.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_005.log index 8e11c36dc1..45c45e8502 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_005.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_005.log @@ -61,17 +61,19 @@ These are your past 4 actions: Memory 0: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - To begin solving the task, I need to create a new shell script named 'hello.sh'. This script should contain a simple command to print 'hello'. I will use the `write` command to create this file and insert the necessary bash script code. + I need to create a shell script named 'hello.sh' that prints 'hello' without asking for confirmation. I will need to ensure that the script is executable. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -79,17 +81,19 @@ extras: Memory 1: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I have created the file 'hello.sh' but I have not yet written any content into it. The task requires me to write a shell script that prints 'hello'. I need to add the appropriate bash command to this file to fulfill the requirement. The command to print in bash is `echo`. I will write this command into 'hello.sh'. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -97,17 +101,19 @@ extras: Memory 2: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - Based on the previous actions, it appears that the file 'hello.sh' has been created but no content has been written into it yet. The task requires a shell script that prints 'hello'. I need to write the appropriate bash command into 'hello.sh' to fulfill this requirement. The command to print in bash is `echo "hello"`. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -115,20 +121,21 @@ extras: Memory 3: Previous Action: -action: read +source: EventSource.AGENT +action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - Based on the previous actions, it seems that the file 'hello.sh' has been created but the content has not been verified yet. The task requires a shell script that prints 'hello'. I need to read the content of 'hello.sh' to ensure that the correct command `echo "hello"` has been written into it. If the content is correct, I can then proceed to test the script to confirm it behaves as expected. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: -observation: read -content: echo "hello" - +source: EventSource.AGENT +observation: write +content: extras: path: hello.sh ======= End Actions ======= diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_006.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_006.log index 780f491092..50f5b6ab3a 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_006.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_006.log @@ -61,17 +61,19 @@ These are your past 4 actions: Memory 0: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I have created the file 'hello.sh' but I have not yet written any content into it. The task requires me to write a shell script that prints 'hello'. I need to add the appropriate bash command to this file to fulfill the requirement. The command to print in bash is `echo`. I will write this command into 'hello.sh'. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -79,17 +81,19 @@ extras: Memory 1: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - Based on the previous actions, it appears that the file 'hello.sh' has been created but no content has been written into it yet. The task requires a shell script that prints 'hello'. I need to write the appropriate bash command into 'hello.sh' to fulfill this requirement. The command to print in bash is `echo "hello"`. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -97,38 +101,43 @@ extras: Memory 2: Previous Action: -action: read +source: EventSource.AGENT +action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - Based on the previous actions, it seems that the file 'hello.sh' has been created but the content has not been verified yet. The task requires a shell script that prints 'hello'. I need to read the content of 'hello.sh' to ensure that the correct command `echo "hello"` has been written into it. If the content is correct, I can then proceed to test the script to confirm it behaves as expected. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: -observation: read -content: echo "hello" - +source: EventSource.AGENT +observation: write +content: extras: path: hello.sh Memory 3: Previous Action: -action: run +source: EventSource.AGENT +action: write args: - command: bash hello.sh - background: False - thought: + path: hello.sh + start: 0 + end: -1 + thought: Thoughts: + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. + + Action: Output from Action: -observation: run -content: hello +source: EventSource.AGENT +observation: write +content: extras: - command_id: -1 - command: bash hello.sh - exit_code: 0 + path: hello.sh ======= End Actions ======= Use these memories to provide additional context to the problem you are solving. Remember that you have already completed these steps so you do not need to perform them again. diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_007.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_007.log index e1ba1d542d..568f3159ec 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_007.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_007.log @@ -61,17 +61,19 @@ These are your past 4 actions: Memory 0: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. This involves editing the existing script. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -79,17 +81,19 @@ extras: Memory 1: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. Since the script is already created and made executable, I should simply edit the script to include the command to print 'hello'. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -97,17 +101,19 @@ extras: Memory 2: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -115,21 +121,21 @@ extras: Memory 3: Previous Action: -action: write +source: EventSource.AGENT +action: run args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: + command: chmod +x hello.sh + background: False + thought: Output from Action: -observation: write +source: EventSource.AGENT +observation: run content: extras: - path: hello.sh + command_id: -1 + command: chmod +x hello.sh + exit_code: 0 ======= End Actions ======= Use these memories to provide additional context to the problem you are solving. Remember that you have already completed these steps so you do not need to perform them again. diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_008.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_008.log index bc3e180089..927821a6c5 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_008.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_008.log @@ -61,17 +61,19 @@ These are your past 4 actions: Memory 0: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. This involves editing the existing script. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -79,17 +81,19 @@ extras: Memory 1: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. Since the script is already created and made executable, I should simply edit the script to include the command to print 'hello'. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -97,39 +101,39 @@ extras: Memory 2: Previous Action: -action: write +source: EventSource.AGENT +action: run args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: + command: chmod +x hello.sh + background: False + thought: Output from Action: -observation: write +source: EventSource.AGENT +observation: run content: extras: - path: hello.sh + command_id: -1 + command: chmod +x hello.sh + exit_code: 0 Memory 3: Previous Action: -action: write +source: EventSource.AGENT +action: run args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: + command: bash hello.sh + background: False + thought: Output from Action: -observation: write -content: +source: EventSource.AGENT +observation: run +content: hello extras: - path: hello.sh + command_id: -1 + command: bash hello.sh + exit_code: 0 ======= End Actions ======= Use these memories to provide additional context to the problem you are solving. Remember that you have already completed these steps so you do not need to perform them again. @@ -197,95 +201,3 @@ Be very strict about the formatting that you use and make sure you follow the gu NEVER output multiple commands. ONLY take ONE STEP at a time. When you have completed your task run the "exit" command. Begin with your thought about the next step and then come up with an action to perform your thought. - ----------- - - -You did not include any action to take in your most recent output: - -===== Output ====== -Thoughts: -I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - -Action: -I will edit the 'hello.sh' script to include the command to print 'hello' without asking for confirmation. -==== End Output === - -Remember these are the custom commands you can use: -DOCUMENTATION: -It is recommend that you use the commands provided for interacting with files and your directory because they have been specially built for you. -They will make it much easier for you to look at files and make changes. Using these commands will help you be better at your task. -You can open an file by using either the read or write operations. -- If a file already exists you should read it before making any changes. Use the `edit` command to make changes once you have read it. -- If you are creating a new file use the write command. Use the `edit` command to make changes once you have created the new file. - -Commands: -exit - Executed when task is complete -read [] [] - Shows a given file's contents starting from up to . Default: start_line = 0, end_line = -1. By default the whole file will be read. -write [] [] - Modifies a by replacing the current lines between and with . Default start_line = 0 and end_line = -1. Calling this with no line args will replace the whole file. -browse - Returns the text version of any url, this can be useful to look up documentation or finding issues on github -scroll_up - Takes no arguments. This will scroll up and show you the 100 lines above your current lines -scroll_down - Takes no arguments. This will scroll down and show you the 100 lines below your current lines -edit - This will modify lines in the currently open file. use start_line and end_line to designate which lines to change and then write the multiline changes. Set end_line to -1 to denote the end of the file -goto - This will take you directly to a line and show you the 100 lines below it. - - You can use any bash command you need (cd, ls, rm, grep, dir, mv, wget, git, zip, etc.) with their arguments included -pip install - You can use this to import python packages. Make sure you include the correct package name when using this command. -ls - Use the ls command to view all the files in your current directory, this is a good starting point. -NOT ALLOWED - You cannot use interactive commands like python or node -Custom bash commands: -None - - -The following commands require an open file to be used: edit, scroll_up, scroll_down, goto -To modify the current file use 'edit'. To move through the current file use 'goto' or 'scroll_up'/'scroll_down' -when using write and edit do not surround the code with any "" just write the code. - - -Lets try that again, it is very important that you adhere to the output format -This time, be sure to use the exact format below, replacing anything in <> with the appropriate value(s): -RESPONSE FORMAT: -This is the format of the response you will make in order to solve the current issue. -You will be given multiple iterations to complete this task so break it into steps and solve them one by one. - -Your output must contain the following: -- First, thoughts about what your next action should be and plan it out. - - You will have a memory of your thoughts so you can use this to remember things for the next step. - - Use your thoughts to think about what you are currently doing, what you have done on prior steps and how that relates to solving the problem. -- Second, create a piece of code that will execute your next action based on the thoughts you have. - - Remember that you can only have one action for each thought, do not include multiple actions. - -Your code MUST be surrounded in triple back ticks EXACTLY like this: -``` - -``` - -Notes: -- Adhere to the format so that the program loop continues smoothly, it is very important to only give one command per output. -- DO NOT give more than one command within the triple backticks. This will just throw an error and nothing will happen as a result. -- Do not give multiple code blocks, if you do only the second one will be captured and run, this might give an error if the first one was necessary. -- To execute multiple commands you should write them down in your thoughts section so you can remember it on the next step and execute them then. -- The only commands you are not capable of executing are interactive commands like `python` or `node` by themselves. -- If you think that you have completed the task that has been given to you based on your previous actions and outputs then use ``` exit ``` as the command to let the system know that you are done. -- DO NOT make any copies of your previous memories those will be provided to you at each step, making copies just wastes time and energy. Think smarter not harder. -- The write and edit commands requires proper indentation in the content section ex. `write hw.py def hello(): - print('Hello World')` this is how you would have to format your write command. - - The white spaces matter as the code changes will be added to the code so they must have proper syntax. - -This is a template using the format described above -Items in <> are suggestions for you, fill them out based on the context of the problem you are solving. - -[ FORMAT ] -Thoughts: - - - -Action: -``` - -``` -[ END FORMAT ] - -Do not provide anything extra just your thought and action. - - -It is crucial you use the format provided as the output will be parsed automatically. diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_009.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_009.log index 4be7693b53..080b9f287f 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_009.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_009.log @@ -61,17 +61,19 @@ These are your past 4 actions: Memory 0: Previous Action: +source: EventSource.AGENT action: write args: path: hello.sh start: 0 end: -1 thought: Thoughts: - I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. Since the script is already created and made executable, I should simply edit the script to include the command to print 'hello'. + I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: Output from Action: +source: EventSource.AGENT observation: write content: extras: @@ -79,57 +81,57 @@ extras: Memory 1: Previous Action: -action: write +source: EventSource.AGENT +action: run args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: + command: chmod +x hello.sh + background: False + thought: Output from Action: -observation: write +source: EventSource.AGENT +observation: run content: extras: - path: hello.sh + command_id: -1 + command: chmod +x hello.sh + exit_code: 0 Memory 2: Previous Action: -action: write +source: EventSource.AGENT +action: run args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: + command: bash hello.sh + background: False + thought: Output from Action: -observation: write -content: +source: EventSource.AGENT +observation: run +content: hello extras: - path: hello.sh + command_id: -1 + command: bash hello.sh + exit_code: 0 Memory 3: Previous Action: -action: write +source: EventSource.AGENT +action: run args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to edit the 'hello.sh' script to include the command to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: + command: bash hello.sh + background: False + thought: Output from Action: -observation: write -content: +source: EventSource.AGENT +observation: run +content: hello extras: - path: hello.sh + command_id: -1 + command: bash hello.sh + exit_code: 0 ======= End Actions ======= Use these memories to provide additional context to the problem you are solving. Remember that you have already completed these steps so you do not need to perform them again. diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_010.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_010.log deleted file mode 100644 index 56b649dcf4..0000000000 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_010.log +++ /dev/null @@ -1,199 +0,0 @@ - - ----------- - -SYSTEM INFO: -You am an autonomous coding agent, here to provide solutions for coding issues. -You have been designed to assist you with a wide range of programming tasks, from code editing and debugging to testing and deployment. -You have access to a variety of tools and commands that you can use to help you solve problems efficiently. - -INSTRUCTIONS: -Now, you're going to solve this issue on your own. You can use any bash commands or custom commands you wish to complete your task. Edit all the files you need to and run any checks or tests that you want. -Remember, YOU CAN ONLY ENTER ONE COMMAND AT A TIME. You should always wait for feedback after every command. -When you're satisfied with all of the changes you've made, you can indicate that you are done by running the exit command. -Note however that you cannot use any interactive session commands (e.g. python, vim, node) in this environment, but you can write scripts and run them. E.g. you can write a python script and then run it with `python .py`. - -NOTE ABOUT THE write COMMAND: Indentation really matters! When editing a file, make sure to insert appropriate indentation before each line! - -IMPORTANT TIPS: -1. Reproduce the bug: Always start by trying to replicate the bug that the issue discusses. If the issue includes code for reproducing the bug, we recommend that you re-implement that in your environment and run it to ensure you can reproduce the bug. Then, start trying to fix it. When you think you've fixed the bug, re-run the bug reproduction script to make sure that the issue has indeed been resolved. - If the bug reproduction script does not print anything when it successfully runs, we recommend adding a print("Script completed successfully, no errors.") command at the end of the file, so that you can be sure the script ran fine all the way through. -2. Try different commands: If you run a command and it doesn't work, try running a different command. A command that did not work once will not work the second time unless you modify it. -3. Navigate large files: If you open a file and need to get to an area around a specific line that is not in the first 100 lines, say line 583, you would use the 'read' command like this: 'read 583'. This is a much faster way to read through the file. -4. Handle input files: If the bug reproduction script requires inputting/reading a specific file, such as 'buggy-input.png', and you'd like to understand how to input that file, conduct a search in the existing repository code to see whether someone else has already done that. Do this by running the command: 'search_dir "buggy-input.png"'. If that doesn't work, use the Linux 'find' command. -5. Understand your context: Always make sure to look at the currently open file and the current working directory. The currently open file might be in a different directory than the working directory. -6. Verify your edits: When editing files, it is easy to accidentally specify a wrong line number or to write code with incorrect indentation. Always check the code after you issue an edit to make sure that it reflects what you wanted to accomplish. If it didn't, issue another command to fix it. -7. Thoroughly test your solution: After making any changes to fix a bug, be sure to thoroughly test your solution to ensure the bug has been resolved. Re-run the bug reproduction script and verify that the issue has been addressed. - - -DOCUMENTATION: -It is recommend that you use the commands provided for interacting with files and your directory because they have been specially built for you. -They will make it much easier for you to look at files and make changes. Using these commands will help you be better at your task. -You can open an file by using either the read or write operations. -- If a file already exists you should read it before making any changes. Use the `edit` command to make changes once you have read it. -- If you are creating a new file use the write command. Use the `edit` command to make changes once you have created the new file. - -Commands: -exit - Executed when task is complete -read [] [] - Shows a given file's contents starting from up to . Default: start_line = 0, end_line = -1. By default the whole file will be read. -write [] [] - Modifies a by replacing the current lines between and with . Default start_line = 0 and end_line = -1. Calling this with no line args will replace the whole file. -browse - Returns the text version of any url, this can be useful to look up documentation or finding issues on github -scroll_up - Takes no arguments. This will scroll up and show you the 100 lines above your current lines -scroll_down - Takes no arguments. This will scroll down and show you the 100 lines below your current lines -edit - This will modify lines in the currently open file. use start_line and end_line to designate which lines to change and then write the multiline changes. Set end_line to -1 to denote the end of the file -goto - This will take you directly to a line and show you the 100 lines below it. - - You can use any bash command you need (cd, ls, rm, grep, dir, mv, wget, git, zip, etc.) with their arguments included -pip install - You can use this to import python packages. Make sure you include the correct package name when using this command. -ls - Use the ls command to view all the files in your current directory, this is a good starting point. -NOT ALLOWED - You cannot use interactive commands like python or node -Custom bash commands: -None - - -The following commands require an open file to be used: edit, scroll_up, scroll_down, goto -To modify the current file use 'edit'. To move through the current file use 'goto' or 'scroll_up'/'scroll_down' -when using write and edit do not surround the code with any "" just write the code. - ----------- - -These are your past 4 actions: -===== Previous Actions ===== - -Memory 0: -Previous Action: -action: write -args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: - -Output from Action: -observation: write -content: -extras: - path: hello.sh - -Memory 1: -Previous Action: -action: write -args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: - -Output from Action: -observation: write -content: -extras: - path: hello.sh - -Memory 2: -Previous Action: -action: write -args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to edit the 'hello.sh' script to include the command to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: - -Output from Action: -observation: write -content: -extras: - path: hello.sh - -Memory 3: -Previous Action: -action: write -args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: - -Output from Action: -observation: write -content: -extras: - path: hello.sh -======= End Actions ======= -Use these memories to provide additional context to the problem you are solving. -Remember that you have already completed these steps so you do not need to perform them again. - ----------- - -RESPONSE FORMAT: -This is the format of the response you will make in order to solve the current issue. -You will be given multiple iterations to complete this task so break it into steps and solve them one by one. - -Your output must contain the following: -- First, thoughts about what your next action should be and plan it out. - - You will have a memory of your thoughts so you can use this to remember things for the next step. - - Use your thoughts to think about what you are currently doing, what you have done on prior steps and how that relates to solving the problem. -- Second, create a piece of code that will execute your next action based on the thoughts you have. - - Remember that you can only have one action for each thought, do not include multiple actions. - -Your code MUST be surrounded in triple back ticks EXACTLY like this: -``` - -``` - -Notes: -- Adhere to the format so that the program loop continues smoothly, it is very important to only give one command per output. -- DO NOT give more than one command within the triple backticks. This will just throw an error and nothing will happen as a result. -- Do not give multiple code blocks, if you do only the second one will be captured and run, this might give an error if the first one was necessary. -- To execute multiple commands you should write them down in your thoughts section so you can remember it on the next step and execute them then. -- The only commands you are not capable of executing are interactive commands like `python` or `node` by themselves. -- If you think that you have completed the task that has been given to you based on your previous actions and outputs then use ``` exit ``` as the command to let the system know that you are done. -- DO NOT make any copies of your previous memories those will be provided to you at each step, making copies just wastes time and energy. Think smarter not harder. -- The write and edit commands requires proper indentation in the content section ex. `write hw.py def hello(): - print('Hello World')` this is how you would have to format your write command. - - The white spaces matter as the code changes will be added to the code so they must have proper syntax. - -This is a template using the format described above -Items in <> are suggestions for you, fill them out based on the context of the problem you are solving. - -[ FORMAT ] -Thoughts: - - - -Action: -``` - -``` -[ END FORMAT ] - -Do not provide anything extra just your thought and action. - -You are currently trying to complete this task: -Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point. - -CURRENT WORKSPACE: - Open File: hello.sh on line 0 - You can use these commands with the current file: - Navigation: `scroll_up`, `scroll_down`, and `goto ` - Modification: `edit ` - - -Keep all of the guidelines above in mind when you are thinking and making code. -Please come up with a thought and action based on your current task and latest steps. -Make sure that you do not repeat the same actions, there will not be any changes in result if you do not changes anything. -Be very strict about the formatting that you use and make sure you follow the guidelines. -NEVER output multiple commands. ONLY take ONE STEP at a time. -When you have completed your task run the "exit" command. -Begin with your thought about the next step and then come up with an action to perform your thought. diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_011.log b/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_011.log deleted file mode 100644 index ded1c4b1d1..0000000000 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/prompt_011.log +++ /dev/null @@ -1,199 +0,0 @@ - - ----------- - -SYSTEM INFO: -You am an autonomous coding agent, here to provide solutions for coding issues. -You have been designed to assist you with a wide range of programming tasks, from code editing and debugging to testing and deployment. -You have access to a variety of tools and commands that you can use to help you solve problems efficiently. - -INSTRUCTIONS: -Now, you're going to solve this issue on your own. You can use any bash commands or custom commands you wish to complete your task. Edit all the files you need to and run any checks or tests that you want. -Remember, YOU CAN ONLY ENTER ONE COMMAND AT A TIME. You should always wait for feedback after every command. -When you're satisfied with all of the changes you've made, you can indicate that you are done by running the exit command. -Note however that you cannot use any interactive session commands (e.g. python, vim, node) in this environment, but you can write scripts and run them. E.g. you can write a python script and then run it with `python .py`. - -NOTE ABOUT THE write COMMAND: Indentation really matters! When editing a file, make sure to insert appropriate indentation before each line! - -IMPORTANT TIPS: -1. Reproduce the bug: Always start by trying to replicate the bug that the issue discusses. If the issue includes code for reproducing the bug, we recommend that you re-implement that in your environment and run it to ensure you can reproduce the bug. Then, start trying to fix it. When you think you've fixed the bug, re-run the bug reproduction script to make sure that the issue has indeed been resolved. - If the bug reproduction script does not print anything when it successfully runs, we recommend adding a print("Script completed successfully, no errors.") command at the end of the file, so that you can be sure the script ran fine all the way through. -2. Try different commands: If you run a command and it doesn't work, try running a different command. A command that did not work once will not work the second time unless you modify it. -3. Navigate large files: If you open a file and need to get to an area around a specific line that is not in the first 100 lines, say line 583, you would use the 'read' command like this: 'read 583'. This is a much faster way to read through the file. -4. Handle input files: If the bug reproduction script requires inputting/reading a specific file, such as 'buggy-input.png', and you'd like to understand how to input that file, conduct a search in the existing repository code to see whether someone else has already done that. Do this by running the command: 'search_dir "buggy-input.png"'. If that doesn't work, use the Linux 'find' command. -5. Understand your context: Always make sure to look at the currently open file and the current working directory. The currently open file might be in a different directory than the working directory. -6. Verify your edits: When editing files, it is easy to accidentally specify a wrong line number or to write code with incorrect indentation. Always check the code after you issue an edit to make sure that it reflects what you wanted to accomplish. If it didn't, issue another command to fix it. -7. Thoroughly test your solution: After making any changes to fix a bug, be sure to thoroughly test your solution to ensure the bug has been resolved. Re-run the bug reproduction script and verify that the issue has been addressed. - - -DOCUMENTATION: -It is recommend that you use the commands provided for interacting with files and your directory because they have been specially built for you. -They will make it much easier for you to look at files and make changes. Using these commands will help you be better at your task. -You can open an file by using either the read or write operations. -- If a file already exists you should read it before making any changes. Use the `edit` command to make changes once you have read it. -- If you are creating a new file use the write command. Use the `edit` command to make changes once you have created the new file. - -Commands: -exit - Executed when task is complete -read [] [] - Shows a given file's contents starting from up to . Default: start_line = 0, end_line = -1. By default the whole file will be read. -write [] [] - Modifies a by replacing the current lines between and with . Default start_line = 0 and end_line = -1. Calling this with no line args will replace the whole file. -browse - Returns the text version of any url, this can be useful to look up documentation or finding issues on github -scroll_up - Takes no arguments. This will scroll up and show you the 100 lines above your current lines -scroll_down - Takes no arguments. This will scroll down and show you the 100 lines below your current lines -edit - This will modify lines in the currently open file. use start_line and end_line to designate which lines to change and then write the multiline changes. Set end_line to -1 to denote the end of the file -goto - This will take you directly to a line and show you the 100 lines below it. - - You can use any bash command you need (cd, ls, rm, grep, dir, mv, wget, git, zip, etc.) with their arguments included -pip install - You can use this to import python packages. Make sure you include the correct package name when using this command. -ls - Use the ls command to view all the files in your current directory, this is a good starting point. -NOT ALLOWED - You cannot use interactive commands like python or node -Custom bash commands: -None - - -The following commands require an open file to be used: edit, scroll_up, scroll_down, goto -To modify the current file use 'edit'. To move through the current file use 'goto' or 'scroll_up'/'scroll_down' -when using write and edit do not surround the code with any "" just write the code. - ----------- - -These are your past 4 actions: -===== Previous Actions ===== - -Memory 0: -Previous Action: -action: write -args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: - -Output from Action: -observation: write -content: -extras: - path: hello.sh - -Memory 1: -Previous Action: -action: write -args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to edit the 'hello.sh' script to include the command to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: - -Output from Action: -observation: write -content: -extras: - path: hello.sh - -Memory 2: -Previous Action: -action: write -args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: - -Output from Action: -observation: write -content: -extras: - path: hello.sh - -Memory 3: -Previous Action: -action: write -args: - path: hello.sh - start: 0 - end: -1 - thought: Thoughts: - I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - - Action: - -Output from Action: -observation: write -content: -extras: - path: hello.sh -======= End Actions ======= -Use these memories to provide additional context to the problem you are solving. -Remember that you have already completed these steps so you do not need to perform them again. - ----------- - -RESPONSE FORMAT: -This is the format of the response you will make in order to solve the current issue. -You will be given multiple iterations to complete this task so break it into steps and solve them one by one. - -Your output must contain the following: -- First, thoughts about what your next action should be and plan it out. - - You will have a memory of your thoughts so you can use this to remember things for the next step. - - Use your thoughts to think about what you are currently doing, what you have done on prior steps and how that relates to solving the problem. -- Second, create a piece of code that will execute your next action based on the thoughts you have. - - Remember that you can only have one action for each thought, do not include multiple actions. - -Your code MUST be surrounded in triple back ticks EXACTLY like this: -``` - -``` - -Notes: -- Adhere to the format so that the program loop continues smoothly, it is very important to only give one command per output. -- DO NOT give more than one command within the triple backticks. This will just throw an error and nothing will happen as a result. -- Do not give multiple code blocks, if you do only the second one will be captured and run, this might give an error if the first one was necessary. -- To execute multiple commands you should write them down in your thoughts section so you can remember it on the next step and execute them then. -- The only commands you are not capable of executing are interactive commands like `python` or `node` by themselves. -- If you think that you have completed the task that has been given to you based on your previous actions and outputs then use ``` exit ``` as the command to let the system know that you are done. -- DO NOT make any copies of your previous memories those will be provided to you at each step, making copies just wastes time and energy. Think smarter not harder. -- The write and edit commands requires proper indentation in the content section ex. `write hw.py def hello(): - print('Hello World')` this is how you would have to format your write command. - - The white spaces matter as the code changes will be added to the code so they must have proper syntax. - -This is a template using the format described above -Items in <> are suggestions for you, fill them out based on the context of the problem you are solving. - -[ FORMAT ] -Thoughts: - - - -Action: -``` - -``` -[ END FORMAT ] - -Do not provide anything extra just your thought and action. - -You are currently trying to complete this task: -Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point. - -CURRENT WORKSPACE: - Open File: hello.sh on line 0 - You can use these commands with the current file: - Navigation: `scroll_up`, `scroll_down`, and `goto ` - Modification: `edit ` - - -Keep all of the guidelines above in mind when you are thinking and making code. -Please come up with a thought and action based on your current task and latest steps. -Make sure that you do not repeat the same actions, there will not be any changes in result if you do not changes anything. -Be very strict about the formatting that you use and make sure you follow the guidelines. -NEVER output multiple commands. ONLY take ONE STEP at a time. -When you have completed your task run the "exit" command. -Begin with your thought about the next step and then come up with an action to perform your thought. diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_001.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_001.log index a926628b03..2924117174 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_001.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/response_001.log @@ -1,8 +1,7 @@ Thoughts: -To begin solving the task, I need to create a new shell script named 'hello.sh'. This script should contain a simple command to print 'hello'. I will use the `write` command to create this file and insert the necessary bash script code. +I need to create a shell script named 'hello.sh' that prints 'hello' without asking for confirmation. I will need to ensure that the script is executable. Action: ``` -write hello.sh #!/bin/bash -echo 'hello' +write hello.sh "echo 'hello'" ``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_002.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_002.log index 0f8a846b3d..c3b065960d 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_002.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/response_002.log @@ -1,7 +1,7 @@ Thoughts: -I have created the file 'hello.sh' but I have not yet written any content into it. The task requires me to write a shell script that prints 'hello'. I need to add the appropriate bash command to this file to fulfill the requirement. The command to print in bash is `echo`. I will write this command into 'hello.sh'. +I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: ``` -write hello.sh echo "hello" +edit 0 -1 "echo 'hello'" ``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_003.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_003.log index d0263f1a23..c3b065960d 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_003.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/response_003.log @@ -1,7 +1,7 @@ Thoughts: -Based on the previous actions, it appears that the file 'hello.sh' has been created but no content has been written into it yet. The task requires a shell script that prints 'hello'. I need to write the appropriate bash command into 'hello.sh' to fulfill this requirement. The command to print in bash is `echo "hello"`. +I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: ``` -write hello.sh echo "hello" +edit 0 -1 "echo 'hello'" ``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_004.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_004.log index 359d29a805..c3b065960d 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_004.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/response_004.log @@ -1,7 +1,7 @@ Thoughts: -Based on the previous actions, it seems that the file 'hello.sh' has been created but the content has not been verified yet. The task requires a shell script that prints 'hello'. I need to read the content of 'hello.sh' to ensure that the correct command `echo "hello"` has been written into it. If the content is correct, I can then proceed to test the script to confirm it behaves as expected. +I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: ``` -read hello.sh +edit 0 -1 "echo 'hello'" ``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_005.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_005.log index f54fdde94e..c3b065960d 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_005.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/response_005.log @@ -1,7 +1,7 @@ Thoughts: -The content of 'hello.sh' has been verified and contains the correct command `echo "hello"` which fulfills the task requirement to print 'hello'. The next logical step is to test the script to ensure it behaves as expected when executed. This will confirm that the script is functional and meets the requirements specified. +I need to add the code to the 'hello.sh' script that will print 'hello' without asking for confirmation. I will ensure that the script is executable after making the necessary changes. Action: ``` -bash hello.sh +edit 0 -1 "echo 'hello'" ``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_006.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_006.log index 8ac790ef74..24af89f73c 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_006.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/response_006.log @@ -1,7 +1,7 @@ Thoughts: -The shell script 'hello.sh' has been successfully created and tested, and it outputs 'hello' as expected. Since the task was to write a shell script that prints 'hello' and this has been achieved, there are no further modifications or actions required on the script. Therefore, I should conclude this task. +I have already written the initial version of the 'hello.sh' script that prints 'hello' without asking for confirmation. I need to ensure that the script is executable to run successfully. Action: ``` -exit +chmod +x hello.sh ``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_007.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_007.log index 6949b125d4..d86e7c959f 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_007.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/response_007.log @@ -1,5 +1,7 @@ Thoughts: -I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. +I have already added the code to the 'hello.sh' script that prints 'hello' without asking for confirmation. The script is also made executable. The next step is to run the script to ensure it functions as expected. Action: -I will edit the 'hello.sh' script to include the command to print 'hello' without asking for confirmation. +``` +bash hello.sh +``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_008.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_008.log index e569fe594f..defb21379b 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_008.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/response_008.log @@ -1,7 +1,7 @@ Thoughts: -I need to edit the 'hello.sh' script to include the command to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. +I have already created the 'hello.sh' script that prints 'hello' without asking for confirmation. The script is also made executable. The next step is to ensure that the script runs successfully without any issues. Action: ``` -edit 0 -1 "echo 'hello'" +bash hello.sh ``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_009.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_009.log index 310fde5701..6bade8b475 100644 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_009.log +++ b/tests/integration/mock/SWEAgent/test_write_simple_script/response_009.log @@ -1,7 +1,7 @@ Thoughts: -I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. +I have already created the 'hello.sh' script that prints 'hello' without asking for confirmation. The script is executable, and I have run it successfully. The next step is to finalize the task and exit the current environment. Action: ``` -edit 0 -1 "echo 'hello'" +exit ``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_010.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_010.log deleted file mode 100644 index 310fde5701..0000000000 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_010.log +++ /dev/null @@ -1,7 +0,0 @@ -Thoughts: -I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - -Action: -``` -edit 0 -1 "echo 'hello'" -``` diff --git a/tests/integration/mock/SWEAgent/test_write_simple_script/response_011.log b/tests/integration/mock/SWEAgent/test_write_simple_script/response_011.log deleted file mode 100644 index 22f89941a2..0000000000 --- a/tests/integration/mock/SWEAgent/test_write_simple_script/response_011.log +++ /dev/null @@ -1,9 +0,0 @@ -Thoughts: -I need to add the command in the 'hello.sh' script to print 'hello' without asking for confirmation. Since the script is already created, made executable, and the initial content was added, I should now insert the command to print 'hello' into the script. - -Action: -I will add the command to print 'hello' into the 'hello.sh' script. - -``` -edit 0 -1 "echo 'hello'" -``` diff --git a/tests/unit/test_action_serialization.py b/tests/unit/test_action_serialization.py index 6141a00661..3b7aba31b9 100644 --- a/tests/unit/test_action_serialization.py +++ b/tests/unit/test_action_serialization.py @@ -11,7 +11,11 @@ from opendevin.events.action import ( FileWriteAction, MessageAction, ModifyTaskAction, +) +from opendevin.events.serialization import ( action_from_dict, + event_to_dict, + event_to_memory, ) @@ -23,8 +27,8 @@ def serialization_deserialization(original_action_dict, cls): assert isinstance( action_instance, cls ), f'The action instance should be an instance of {cls.__name__}.' - serialized_action_dict = action_instance.to_dict() - serialized_action_memory = action_instance.to_memory() + serialized_action_dict = event_to_dict(action_instance) + serialized_action_memory = event_to_memory(action_instance) serialized_action_dict.pop('message') assert ( serialized_action_dict == original_action_dict diff --git a/tests/unit/test_event_stream.py b/tests/unit/test_event_stream.py new file mode 100644 index 0000000000..3ad430b9d6 --- /dev/null +++ b/tests/unit/test_event_stream.py @@ -0,0 +1,54 @@ +import json + +import pytest + +from opendevin.events.action import NullAction +from opendevin.events.observation import NullObservation +from opendevin.events.stream import EventSource, EventStream + + +@pytest.mark.asyncio +async def test_basic_flow(): + stream = EventStream('abc') + await stream.add_event(NullAction(), EventSource.AGENT) + assert len(stream._events) == 1 + + +@pytest.mark.asyncio +async def test_stream_storage(): + stream = EventStream('def') + await stream.add_event(NullObservation(''), EventSource.AGENT) + assert len(stream._events) == 1 + content = stream._file_store.read('sessions/def/events/0.json') + assert content is not None + data = json.loads(content) + assert 'timestamp' in data + del data['timestamp'] + assert data == { + 'id': 0, + 'source': 'agent', + 'observation': 'null', + 'content': '', + 'extras': {}, + 'message': 'No observation', + } + + +@pytest.mark.asyncio +async def test_rehydration(): + stream1 = EventStream('es1') + await stream1.add_event(NullObservation('obs1'), EventSource.AGENT) + await stream1.add_event(NullObservation('obs2'), EventSource.AGENT) + assert len(stream1._events) == 2 + + stream2 = EventStream('es2') + assert len(stream2._events) == 0 + await stream2._rehydrate() + assert len(stream2._events) == 0 + + stream1rehydrated = EventStream('es1') + assert len(stream1rehydrated._events) == 0 + await stream1rehydrated._rehydrate() + assert len(stream1rehydrated._events) == 2 + assert stream1rehydrated._events[0].content == 'obs1' + assert stream1rehydrated._events[1].content == 'obs2' diff --git a/tests/unit/test_observation_serialization.py b/tests/unit/test_observation_serialization.py index e92d9645e3..a032e72668 100644 --- a/tests/unit/test_observation_serialization.py +++ b/tests/unit/test_observation_serialization.py @@ -1,6 +1,10 @@ from opendevin.events.observation import ( CmdOutputObservation, Observation, +) +from opendevin.events.serialization import ( + event_to_dict, + event_to_memory, observation_from_dict, ) @@ -19,8 +23,8 @@ def test_observation_serialization_deserialization(): assert isinstance( observation_instance, CmdOutputObservation ), 'The observation instance should be an instance of CmdOutputObservation.' - serialized_observation_dict = observation_instance.to_dict() - serialized_observation_memory = observation_instance.to_memory() + serialized_observation_dict = event_to_dict(observation_instance) + serialized_observation_memory = event_to_memory(observation_instance) assert ( serialized_observation_dict == original_observation_dict ), 'The serialized observation should match the original observation dict.' diff --git a/tests/unit/test_storage.py b/tests/unit/test_storage.py new file mode 100644 index 0000000000..272b648b7e --- /dev/null +++ b/tests/unit/test_storage.py @@ -0,0 +1,67 @@ +import os +import shutil + +import pytest + +from opendevin.storage.local import LocalFileStore +from opendevin.storage.memory import InMemoryFileStore + + +@pytest.fixture +def setup_env(): + os.makedirs('./_test_files_tmp', exist_ok=True) + + yield + + shutil.rmtree('./_test_files_tmp') + + +def test_basic_fileops(setup_env): + filename = 'test.txt' + for store in [LocalFileStore('./_test_files_tmp'), InMemoryFileStore()]: + store.write(filename, 'Hello, world!') + assert store.read(filename) == 'Hello, world!' + assert store.list('') == [filename] + store.delete(filename) + with pytest.raises(FileNotFoundError): + store.read(filename) + + +def test_complex_path_fileops(setup_env): + filenames = ['foo.bar.baz', './foo/bar/baz', 'foo/bar/baz', '/foo/bar/baz'] + for store in [LocalFileStore('./_test_files_tmp'), InMemoryFileStore()]: + for filename in filenames: + store.write(filename, 'Hello, world!') + assert store.read(filename) == 'Hello, world!' + store.delete(filename) + with pytest.raises(FileNotFoundError): + store.read(filename) + + +def test_list(setup_env): + for store in [LocalFileStore('./_test_files_tmp'), InMemoryFileStore()]: + store.write('foo.txt', 'Hello, world!') + store.write('bar.txt', 'Hello, world!') + store.write('baz.txt', 'Hello, world!') + assert store.list('').sort() == ['foo.txt', 'bar.txt', 'baz.txt'].sort() + store.delete('foo.txt') + store.delete('bar.txt') + store.delete('baz.txt') + + +def test_deep_list(setup_env): + for store in [LocalFileStore('./_test_files_tmp'), InMemoryFileStore()]: + store.write('foo/bar/baz.txt', 'Hello, world!') + store.write('foo/bar/qux.txt', 'Hello, world!') + store.write('foo/bar/quux.txt', 'Hello, world!') + assert store.list('') == ['foo'], 'Expected foo, got {} for class {}'.format( + store.list(''), store.__class__ + ) + assert store.list('foo') == ['foo/bar'] + assert ( + store.list('foo/bar').sort() + == ['foo/bar/baz.txt', 'foo/bar/qux.txt', 'foo/bar/quux.txt'].sort() + ) + store.delete('foo/bar/baz.txt') + store.delete('foo/bar/qux.txt') + store.delete('foo/bar/quux.txt')