[go: up one dir, main page]

Skip to content

Commit

Permalink
Adding pre-commit and CI for ruff and mypy (All-Hands-AI#69)
Browse files Browse the repository at this point in the history
* don't modify directories

* oops typo

* dev_config/python

* add config to CI

* bump CI python to 3.10

* 3.11?

* del actions/

* add suggestions

* delete unused code

* missed some

* oops missed another one

* remove a file
  • Loading branch information
geohotstan authored Mar 23, 2024
1 parent 642e1b3 commit fb18221
Show file tree
Hide file tree
Showing 17 changed files with 88 additions and 47 deletions.
20 changes: 18 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Lint
on: [push, pull_request]

jobs:
lint:
lint-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -15,4 +15,20 @@ jobs:
npm ci --legacy-peer-deps
- run: |
cd frontend
npm run lint
npm run lint
lint-python:
name: Lint python
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up python
uses: actions/setup-python@v2
with:
python-version: 3.11
- name: Install dependencies
run: pip install ruff mypy types-requests
- name: Run ruff
run: ruff check --config dev_config/python/ruff.toml opendevin/ server/ agenthub/
- name: Run mypy
run: mypy --config-file dev_config/python/mypy.ini opendevin/ server/ agenthub/
2 changes: 2 additions & 0 deletions agenthub/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from . import langchains_agent
from . import codeact_agent

__all__ = ['langchains_agent', 'codeact_agent']
20 changes: 16 additions & 4 deletions agenthub/codeact_agent/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import os
import re
import argparse
from litellm import completion
from termcolor import colored
from typing import List, Dict

from opendevin.agent import Agent, Message, Role
from opendevin.lib.event import Event
from opendevin.lib.command_manager import CommandManager
from opendevin.sandbox.sandbox import DockerInteractive

assert (
Expand Down Expand Up @@ -93,12 +94,13 @@ def run(self) -> None:
command = re.search(r"<execute>(.*)</execute>", action, re.DOTALL)
if command is not None:
# a command was found
command = command.group(1)
if command.strip() == "exit":
command_group = command.group(1)
if command_group.strip() == "exit":
print(colored("Exit received. Exiting...", "red"))
break
# execute the code
observation = self.env.execute(command)
# TODO: does exit_code get loaded into Message?
exit_code, observation = self.env.execute(command_group)
self._history.append(Message(Role.ASSISTANT, observation))
print(colored("===ENV OBSERVATION:===\n" + observation, "blue"))
else:
Expand All @@ -120,5 +122,15 @@ def chat(self, message: str) -> None:
"""
raise NotImplementedError

# TODO: implement these abstract methods
def add_event(self, event: Event) -> None:
raise NotImplementedError("Implement this abstract method")

def step(self, cmd_mgr: CommandManager) -> Event:
raise NotImplementedError("Implement this abstract method")

def search_memory(self, query: str) -> List[str]:
raise NotImplementedError("Implement this abstract method")


Agent.register("CodeActAgent", CodeActAgent)
6 changes: 2 additions & 4 deletions agenthub/langchains_agent/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import os
import argparse
from typing import List, Dict, Type
from typing import List

from opendevin.agent import Agent, Message
from opendevin.agent import Agent

from agenthub.langchains_agent.utils.agent import Agent as LangchainsAgentImpl
from opendevin.lib.event import Event
Expand Down
2 changes: 1 addition & 1 deletion agenthub/langchains_agent/utils/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
set_debug(True)

from typing import List
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.pydantic_v1 import BaseModel

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
Expand Down
7 changes: 1 addition & 6 deletions agenthub/langchains_agent/utils/memory.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import os
from . import json

import chromadb

from llama_index.core import Document
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core import VectorStoreIndex, StorageContext, load_index_from_storage
from llama_index.core.storage.docstore import SimpleDocumentStore
from llama_index.core.vector_stores import SimpleVectorStore

from llama_index.core import VectorStoreIndex
from llama_index.vector_stores.chroma import ChromaVectorStore

class LongTermMemory:
def __init__(self):
db = chromadb.Client()
self.collection = db.create_collection(name="memories")
vector_store = ChromaVectorStore(chroma_collection=self.collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
self.index = VectorStoreIndex.from_vector_store(vector_store)
self.thought_idx = 0

Expand Down
17 changes: 17 additions & 0 deletions dev_config/python/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.3
hooks:
- id: ruff
entry: ruff check --config dev_config/python/ruff.toml opendevin/ server/ agenthub/
always_run: true
pass_filenames: false

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.9.0
hooks:
- id: mypy
additional_dependencies: [types-requests, types-setuptools]
entry: mypy --config-file dev_config/python/mypy.ini opendevin/ server/ agenthub/
always_run: true
pass_filenames: false
11 changes: 11 additions & 0 deletions dev_config/python/mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[mypy]
warn_unused_configs = True
ignore_missing_imports = True
check_untyped_defs = True
explicit_package_bases = True
warn_unreachable = True
warn_redundant_casts = True
no_implicit_optional = True
strict_optional = True

exclude = agenthub/langchains_agent/regression
3 changes: 3 additions & 0 deletions dev_config/python/ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exclude = [
"agenthub/langchains_agent/regression/",
]
5 changes: 2 additions & 3 deletions opendevin/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from .lib.event import Event
from .lib.command_manager import CommandManager
from .controller import AgentController

class Role(Enum):
SYSTEM = "system" # system message for LLM
Expand Down Expand Up @@ -79,7 +78,7 @@ def complete(self) -> bool:
return self._complete

@property
def history(self) -> List[str]:
def history(self) -> List[Message]:
"""
Provides the history of interactions or state changes since the instruction was initiated.
Expand Down Expand Up @@ -125,7 +124,7 @@ def reset(self) -> None:
to prepare the agent for restarting the instruction or cleaning up before destruction.
"""
self.instruction = None
self.instruction = ''
self._complete = False
self._history = []

Expand Down
1 change: 0 additions & 1 deletion opendevin/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ def maybe_perform_action(self, event):
return out_event

def start_loop(self):
output = None
for i in range(self.max_iterations):
print("STEP", i, flush=True)
log_events = self.command_manager.get_background_events()
Expand Down
1 change: 1 addition & 0 deletions opendevin/lib/actions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from .write import write
from .read import read

__all__ = ['run', 'kill', 'browse', 'write', 'read']
4 changes: 1 addition & 3 deletions opendevin/lib/command_manager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import subprocess
import select
from typing import List

from opendevin.lib.event import Event
Expand Down Expand Up @@ -41,7 +39,7 @@ def run_background(self, command: str) -> str:
self.background_commands[bg_cmd.id] = bg_cmd
return "Background command started. To stop it, send a `kill` action with id " + str(bg_cmd.id)

def kill_command(self, id: int) -> str:
def kill_command(self, id: int):
# TODO: get log events before killing
self.background_commands[id].shell.close()
del self.background_commands[id]
Expand Down
2 changes: 0 additions & 2 deletions opendevin/lib/event.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import os
import json
import opendevin.lib.actions as actions

ACTION_TYPES = ['run', 'kill', 'browse', 'read', 'write', 'recall', 'think', 'summarize', 'output', 'error', 'finish']
Expand Down
4 changes: 2 additions & 2 deletions opendevin/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Type
import argparse

import agenthub # for the agent registry
from opendevin.agent import Agent
from opendevin.controller import AgentController

Expand All @@ -14,7 +14,7 @@

print(f"Running agent {args.agent_cls} (model: {args.model_name}, directory: {args.directory}) with task: \"{args.task}\"")

AgentCls: Agent = Agent.get_cls(args.agent_cls)
AgentCls: Type[Agent] = Agent.get_cls(args.agent_cls)
agent = AgentCls(
instruction=args.task,
workspace_dir=args.directory,
Expand Down
27 changes: 11 additions & 16 deletions opendevin/sandbox/sandbox.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
import os
import pty
import sys
import uuid
import time
import shlex
import select
import subprocess
import docker
import time
from typing import List, Tuple
from typing import Tuple
from collections import namedtuple
import atexit

InputType = namedtuple("InputDtype", ["content"])
OutputType = namedtuple("OutputDtype", ["content"])
InputType = namedtuple("InputType", ["content"])
OutputType = namedtuple("OutputType", ["content"])

CONTAINER_IMAGE = os.getenv("SANDBOX_CONTAINER_IMAGE", "opendevin/sandbox:latest")

class DockerInteractive:

def __init__(
self,
workspace_dir: str = None,
container_image: str = None,
workspace_dir: str | None = None,
container_image: str | None = None,
timeout: int = 120,
id: str = None
id: str | None = None
):
if id is not None:
self.instance_id: str = id
self.instance_id = id
else:
self.instance_id: str = uuid.uuid4()
self.instance_id = str(uuid.uuid4())
if workspace_dir is not None:
assert os.path.exists(workspace_dir), f"Directory {workspace_dir} does not exist."
# expand to absolute path
Expand All @@ -52,7 +48,6 @@ def __init__(
self.container_name = f"sandbox-{self.instance_id}"

self.restart_docker_container()
uid = os.getuid()
self.execute('useradd --shell /bin/bash -u {uid} -o -c \"\" -m devin && su devin')
# regester container cleanup function
atexit.register(self.cleanup)
Expand All @@ -62,9 +57,9 @@ def read_logs(self) -> str:
return ""
logs = ""
while True:
ready_to_read, _, _ = select.select([self.log_generator], [], [], .1)
ready_to_read, _, _ = select.select([self.log_generator], [], [], .1) # type: ignore[has-type]
if ready_to_read:
data = self.log_generator.read(4096)
data = self.log_generator.read(4096) # type: ignore[has-type]
if not data:
break
# FIXME: we're occasionally seeing some escape characters like `\x02` and `\x00` in the logs...
Expand Down Expand Up @@ -171,7 +166,7 @@ def cleanup(self):
print("\nExiting...")
break
if user_input.lower() == "exit":
print(f"Exiting...")
print("Exiting...")
break
exit_code, output = docker_interactive.execute(user_input)
print("exit code:", exit_code)
Expand Down
3 changes: 0 additions & 3 deletions server/server.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import asyncio
import json
import os
from time import sleep
Expand Down Expand Up @@ -56,7 +55,6 @@ async def websocket_endpoint(websocket: WebSocket):
await send_message_to_client(get_error_payload("Failed to start container: " + str(e)))
continue

agent_listener = asyncio.create_task(listen_for_agent_messages())
if action == "terminal":
msg = {
"action": "terminal",
Expand All @@ -67,7 +65,6 @@ async def websocket_endpoint(websocket: WebSocket):
if agent_websocket is None:
await send_message_to_client(get_error_payload("Agent not connected"))
continue
await send_message_to_agent(data)

except WebSocketDisconnect:
print("Client websocket disconnected")
Expand Down

0 comments on commit fb18221

Please sign in to comment.