From f861db667530f4f90211ce985a8347cbf969f010 Mon Sep 17 00:00:00 2001 From: Aleksandar Date: Sun, 12 May 2024 16:58:01 +0100 Subject: [PATCH] Enhance API Documentation (#1727) * Add Server Interaction Guide * Fix style * Remove the server_interaction.md and add docstrings doc * Remove very specific setup for the token from the doc * Fix mdx expression failure * Fix all examples * Fix missing empty args {} * Fix the run example to have and background --- opendevin/server/listen.py | 150 ++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 3 deletions(-) diff --git a/opendevin/server/listen.py b/opendevin/server/listen.py index a1465ad428..4fa81f7c99 100644 --- a/opendevin/server/listen.py +++ b/opendevin/server/listen.py @@ -1,12 +1,11 @@ import json import shutil import uuid +import warnings from pathlib import Path -import warnings - with warnings.catch_warnings(): - warnings.simplefilter("ignore") + warnings.simplefilter('ignore') import litellm from fastapi import Depends, FastAPI, Response, UploadFile, WebSocket, status from fastapi.middleware.cors import CORSMiddleware @@ -39,6 +38,67 @@ security_scheme = HTTPBearer() # This endpoint receives events from the client (i.e. the browser) @app.websocket('/ws') async def websocket_endpoint(websocket: WebSocket): + """ + WebSocket endpoint for receiving events from the client (i.e., the browser). + + Once connected, you can send various actions: + - Initialize the agent: + ```json + {"action": "initialize", "args": {"LLM_MODEL": "ollama/llama3", "AGENT": "CodeActAgent", "LANGUAGE": "en", "LLM_API_KEY": "ollama"}} + ``` + - Start a new development task: + ```json + {"action": "start", "args": {"task": "write a bash script that prints hello"}} + ``` + - Send a message: + ```json + {"action": "message", "args": {"content": "Hello, how are you?"}} + ``` + - Write contents to a file: + ```json + {"action": "write", "args": {"path": "./greetings.txt", "content": "Hello, OpenDevin?"}} + ``` + - Read the contents of a file: + ```json + {"action": "read", "args": {"path": "./greetings.txt"}} + ``` + - Run a command: + ```json + {"action": "run", "args": {"command": "ls -l", "background": false, "thought": ""}} + ``` + - Run an IPython command: + ```json + {"action": "run_ipython", "args": {"command": "print('Hello, IPython!')"}} + ``` + - Kill a background command: + ```json + {"action": "kill", "args": {"id": "command_id"}} + ``` + - Open a web page: + ```json + {"action": "browse", "args": {"url": "https://arxiv.org/html/2402.01030v2"}} + ``` + - Search long-term memory: + ```json + {"action": "recall", "args": {"query": "past projects"}} + ``` + - Add a task to the plan: + ```json + {"action": "add_task", "args": {"task": "Implement feature X"}} + ``` + - Update a task in the plan: + ```json + {"action": "modify_task", "args": {"id": "0", "state": "in_progress", "thought": ""}} + ``` + - Change the agent's state: + ```json + {"action": "change_agent_state", "args": {"state": "paused"}} + ``` + - Finish the task: + ```json + {"action": "finish", "args": {}} + ``` + """ await websocket.accept() sid = get_sid_from_token(websocket.query_params.get('token') or '') if sid == '': @@ -53,6 +113,11 @@ async def websocket_endpoint(websocket: WebSocket): async def get_litellm_models(): """ Get all models supported by LiteLLM. + + To get the models: + ```sh + curl http://localhost:3000/api/litellm-models + ``` """ litellm_model_list = litellm.model_list + list(litellm.model_cost.keys()) litellm_model_list_without_bedrock = bedrock.remove_error_modelId( @@ -68,6 +133,11 @@ async def get_litellm_models(): async def get_agents(): """ Get all agents supported by LiteLLM. + + To get the agents: + ```sh + curl http://localhost:3000/api/agents + ``` """ agents = Agent.list_agents() return agents @@ -80,6 +150,12 @@ async def get_token( """ Generate a JWT for authentication when starting a WebSocket connection. This endpoint checks if valid credentials are provided and uses them to get a session ID. If no valid credentials are provided, it generates a new session ID. + + To obtain an authentication token: + ```sh + curl -H "Authorization: Bearer 5ecRe7" http://localhost:3000/api/auth + ``` + **Note:** If `JWT_SECRET` is set, use its value instead of `5ecRe7`. """ if credentials and credentials.credentials: sid = get_sid_from_token(credentials.credentials) @@ -100,6 +176,14 @@ async def get_token( async def get_messages( credentials: HTTPAuthorizationCredentials = Depends(security_scheme), ): + """ + Get messages. + + To get messages: + ```sh + curl -H "Authorization: Bearer " http://localhost:3000/api/messages + ``` + """ data = [] sid = get_sid_from_token(credentials.credentials) if sid != '': @@ -112,6 +196,14 @@ async def get_messages( async def get_message_total( credentials: HTTPAuthorizationCredentials = Depends(security_scheme), ): + """ + Get total message count. + + To get the total message count: + ```sh + curl -H "Authorization: Bearer " http://localhost:3000/api/messages/total + ``` + """ sid = get_sid_from_token(credentials.credentials) return {'msg_total': message_stack.get_message_total(sid)} @@ -120,6 +212,15 @@ async def get_message_total( async def del_messages( credentials: HTTPAuthorizationCredentials = Depends(security_scheme), ): + """ + Delete messages. + + To delete messages: + ```sh + + curl -X DELETE -H "Authorization: Bearer " http://localhost:3000/api/messages + ``` + """ sid = get_sid_from_token(credentials.credentials) message_stack.del_messages(sid) return {'ok': True} @@ -127,12 +228,28 @@ async def del_messages( @app.get('/api/refresh-files') def refresh_files(): + """ + Refresh files. + + To refresh files: + ```sh + curl http://localhost:3000/api/refresh-files + ``` + """ structure = files.get_folder_structure(Path(str(config.workspace_base))) return structure.to_dict() @app.get('/api/select-file') def select_file(file: str): + """ + Select a file. + + To select a file: + ```sh + curl http://localhost:3000/api/select-file?file= + ``` + """ try: workspace_base = config.workspace_base file_path = Path(workspace_base, file) @@ -152,6 +269,14 @@ def select_file(file: str): @app.post('/api/upload-file') async def upload_file(file: UploadFile): + """ + Upload a file. + + To upload a file: + ```sh + curl -X POST -F "file=@" http://localhost:3000/api/upload-file + ``` + """ try: workspace_base = config.workspace_base file_path = Path(workspace_base, file.filename) @@ -172,6 +297,14 @@ async def upload_file(file: UploadFile): def get_plan( credentials: HTTPAuthorizationCredentials = Depends(security_scheme), ): + """ + Get plan. + + To get the plan: + ```sh + curl -H "Authorization: Bearer " http://localhost:3000/api/plan + ``` + """ sid = get_sid_from_token(credentials.credentials) agent = agent_manager.sid_to_agent[sid] controller = agent.controller @@ -192,11 +325,22 @@ def get_plan( @app.get('/api/defaults') async def appconfig_defaults(): + """ + Get default configurations. + + To get the default configurations: + ```sh + curl http://localhost:3000/api/defaults + ``` + """ return config.defaults_dict @app.get('/') async def docs_redirect(): + """ + Redirect to the API documentation. + """ response = RedirectResponse(url='/index.html') return response