From 5e42f140cb8ea5df19856db364bf96c60847b999 Mon Sep 17 00:00:00 2001 From: tobitege Date: Sat, 8 Jun 2024 04:13:11 +0200 Subject: [PATCH] fix: hide special paths; sort models (#2325) --- opendevin/runtime/files.py | 25 +++++++++++++++++++ opendevin/runtime/server/files.py | 29 ++++++++++++++++++++++ opendevin/server/README.md | 15 ++++++++--- opendevin/server/listen.py | 41 ++++++++++++++++++++++++++++--- 4 files changed, 104 insertions(+), 6 deletions(-) diff --git a/opendevin/runtime/files.py b/opendevin/runtime/files.py index d7072a4239..0b9ef1860b 100644 --- a/opendevin/runtime/files.py +++ b/opendevin/runtime/files.py @@ -34,6 +34,31 @@ def get_folder_structure(workdir: Path) -> WorkspaceFile: root = WorkspaceFile(name=workdir.name, children=[]) for item in workdir.iterdir(): if item.is_dir(): + # Ignore special folders + if item.parts[-1] in ( + '.git', + '.DS_Store', + '.svn', + '.hg', + '.idea', + '.vscode', + '.settings', + '.pytest_cache', + '__pycache__', + 'node_modules', + 'vendor', + 'build', + 'dist', + 'bin', + 'logs', + 'log', + 'tmp', + 'temp', + 'coverage', + 'venv', + 'env', + ): + continue dir = get_folder_structure(item) if dir.children: root.children.append(dir) diff --git a/opendevin/runtime/server/files.py b/opendevin/runtime/server/files.py index a2c1e35b8c..7298f2d5a1 100644 --- a/opendevin/runtime/server/files.py +++ b/opendevin/runtime/server/files.py @@ -33,6 +33,35 @@ def resolve_path(file_path, working_directory): # Get path relative to host path_in_host_workspace = Path(config.workspace_base) / path_in_workspace + # Prevent special folders + if path_in_host_workspace: + path_obj = Path(path_in_host_workspace) + if path_obj: + if path_obj.parts[-1] in ( + '.git', + '.DS_Store', + '.svn', + '.hg', + '.idea', + '.vscode', + '.settings', + '.pytest_cache', + '__pycache__', + 'node_modules', + 'vendor', + 'build', + 'dist', + 'bin', + 'logs', + 'log', + 'tmp', + 'temp', + 'coverage', + 'venv', + 'env', + ): + raise PermissionError('Invalid path.') + return path_in_host_workspace diff --git a/opendevin/server/README.md b/opendevin/server/README.md index 2230d710f9..e2fdd9da04 100644 --- a/opendevin/server/README.md +++ b/opendevin/server/README.md @@ -3,6 +3,7 @@ This is a WebSocket server that executes tasks using an agent. ## Install + Follow the instructions in the base README.md to install dependencies and set up. ## Start the Server @@ -13,7 +14,7 @@ uvicorn opendevin.server.listen:app --reload --port 3000 ## Test the Server -You can use `websocat` to test the server: https://github.com/vi/websocat +You can use [`websocat`](https://github.com/vi/websocat) to test the server. ```sh websocat ws://127.0.0.1:3000/ws @@ -24,23 +25,28 @@ websocat ws://127.0.0.1:3000/ws ```sh LLM_API_KEY=sk-... # Your OpenAI API Key -LLM_MODEL=gpt-4o # Default model for the agent to use -WORKSPACE_BASE=/path/to/your/workspace # Default path to model's workspace +LLM_MODEL=gpt-4o # Default model for the agent to use +WORKSPACE_BASE=/path/to/your/workspace # Default absolute path to workspace ``` ## API Schema + There are two types of messages that can be sent to, or received from, the server: + * Actions * Observations ### Actions + An action has three parts: + * `action`: The action to be taken * `args`: The arguments for the action * `message`: A friendly message that can be put in the chat log There are several kinds of actions. Their arguments are listed below. This list may grow over time. + * `initialize` - initializes the agent. Only sent by client. * `model` - the name of the model to use * `directory` - the path to the workspace @@ -66,7 +72,9 @@ This list may grow over time. * `finish` - agent signals that the task is completed ### Observations + An observation has four parts: + * `observation`: The observation type * `content`: A string representing the observed data * `extras`: additional structured data @@ -74,6 +82,7 @@ An observation has four parts: There are several kinds of observations. Their extras are listed below. This list may grow over time. + * `read` - the content of a file * `path` - the path of the file read * `browse` - the HTML content of a url diff --git a/opendevin/server/listen.py b/opendevin/server/listen.py index c855f721ba..a6eae18fb3 100644 --- a/opendevin/server/listen.py +++ b/opendevin/server/listen.py @@ -6,6 +6,8 @@ from opendevin.server.data_models.feedback import FeedbackDataModel, store_feedb with warnings.catch_warnings(): warnings.simplefilter('ignore') import litellm +from pathlib import Path + from fastapi import FastAPI, Request, Response, UploadFile, WebSocket, status from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse @@ -190,7 +192,7 @@ async def get_litellm_models(): bedrock_model_list = bedrock.list_foundation_models() model_list = litellm_model_list_without_bedrock + bedrock_model_list - return list(set(model_list)) + return list(sorted(set(model_list))) @app.get('/api/options/agents') @@ -203,7 +205,7 @@ async def get_agents(): curl http://localhost:3000/api/agents ``` """ - agents = Agent.list_agents() + agents = sorted(Agent.list_agents()) return agents @@ -223,8 +225,41 @@ def list_files(request: Request, path: str = '/'): content={'error': 'Runtime not yet initialized'}, ) + exclude_list = ( + '.git', + '.DS_Store', + '.svn', + '.hg', + '.idea', + '.vscode', + '.settings', + '.pytest_cache', + '__pycache__', + 'node_modules', + 'vendor', + 'build', + 'dist', + 'bin', + 'logs', + 'log', + 'tmp', + 'temp', + 'coverage', + 'venv', + 'env', + ) + try: - return request.state.session.agent_session.runtime.file_store.list(path) + entries = request.state.session.agent_session.runtime.file_store.list(path) + + # Filter entries, excluding special folders + if entries: + return [ + entry + for entry in entries + if Path(entry).parts and Path(entry).parts[-1] not in exclude_list + ] + return [] except Exception as e: logger.error(f'Error refreshing files: {e}', exc_info=False) error_msg = f'Error refreshing files: {e}'