Compare commits

...

7 Commits

Author SHA1 Message Date
huybery 31ba53f9fe fix: Error: EACCES: permission denied for corepack 2024-04-05 13:56:23 +08:00
iFurySt dcaf51bc9e fix: add the community-maintained model list (#654) 2024-04-04 23:21:17 -04:00
Engel Nyst 12ddd973b5 Remove md around json (#685) 2024-04-04 23:04:34 -04:00
Anas DORBANI c834aa7275 enable build & run tests for the pull_requests (#745) 2024-04-05 02:24:27 +00:00
Anas DORBANI 8c2b4f5fde Update and fix Makefile (#743) 2024-04-05 02:08:23 +00:00
Alex Bäuerle 8ec24ab7ea feat: start implementing new frontend layout (#737) 2024-04-04 21:45:28 -04:00
Anas DORBANI 5ec0e5b7ec Switch to Poetry (#378)
* create the pyproject file

* Fix the pyproject.toml file

* Update Makefile

* adapt makefile

* fix some execution issues

* Untrack lock files and wait for the backend to get start before frontend

* Remove LangChain dependencies

* Add github action for pytest

* add missing dependency

* rebase and fix the versions adding lock file

* add torch and pymupdfb deps

* some conflicts fixes

* Add dependencies evaluation group

* add poetry.lock

* Fix unexpected operator

---------

Co-authored-by: Robert Brennan <contact@rbren.io>
2024-04-05 00:27:29 +00:00
21 changed files with 6687 additions and 4988 deletions
+17
View File
@@ -0,0 +1,17 @@
name: Build & Run Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.11'
- name: Run tests
run: |
make build
poetry run pytest ./tests
+2 -1
View File
@@ -100,7 +100,7 @@ ipython_config.py
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
@@ -128,6 +128,7 @@ venv/
ENV/
env.bak/
venv.bak/
*venv/
# Spyder project settings
.spyderproject
+19 -14
View File
@@ -8,6 +8,7 @@ FRONTEND_PORT = 3001
DEFAULT_WORKSPACE_DIR = "./workspace"
DEFAULT_MODEL = "gpt-4-0125-preview"
CONFIG_FILE = config.toml
PRECOMMIT_CONFIG_PATH = "./dev_config/python/.pre-commit-config.yaml"
# Build
build:
@@ -15,47 +16,50 @@ build:
@echo "Pulling Docker image..."
@docker pull $(DOCKER_IMAGE)
@echo "Installing Python dependencies..."
@python -m pip install pipenv
@python -m pipenv install -v
@curl -sSL https://install.python-poetry.org | python3 -
@poetry install --without evaluation
@echo "Activating Poetry shell..."
@echo "Installing pre-commit hooks..."
@poetry run pre-commit install --config $(PRECOMMIT_CONFIG_PATH)
@echo "Setting up frontend environment..."
@echo "Detect Node.js version..."
@cd frontend && node ./scripts/detect-node-version.js
@cd frontend && if [ -f node_modules/.package-lock.json ]; then \
echo "This project currently uses "pnpm" for dependency management. It has detected that dependencies were previously installed using "npm" and has automatically deleted the "node_modules" directory to prevent unnecessary conflicts."; \
echo "This project currently uses \"pnpm\" for dependency management. It has detected that dependencies were previously installed using \"npm\" and has automatically deleted the \"node_modules\" directory to prevent unnecessary conflicts."; \
rm -rf node_modules; \
fi
@which corepack > /dev/null || (echo "Installing corepack..." && npm install -g corepack)
@cd frontend && corepack enable && pnpm install && pnpm run make-i18n
@cd frontend && sudo corepack enable && pnpm install && pnpm run make-i18n
# Start backend
start-backend:
@echo "Starting backend..."
@python -m pipenv run uvicorn opendevin.server.listen:app --port $(BACKEND_PORT)
@poetry run uvicorn opendevin.server.listen:app --port $(BACKEND_PORT)
# Start frontend
start-frontend:
@echo "Starting frontend..."
@cd frontend && BACKEND_HOST=$(BACKEND_HOST) FRONTEND_PORT=$(FRONTEND_PORT) npm run start
@cd frontend && BACKEND_HOST=$(BACKEND_HOST) FRONTEND_PORT=$(FRONTEND_PORT) pnpm run start
# Run the app
run:
@echo "Running the app..."
@if [ "$(OS)" == "Windows_NT" ]; then \
@if [ "$(OS)" = "Windows_NT" ]; then \
echo "`make run` is not supported on Windows. Please run `make start-frontend` and `make start-backend` separately."; \
exit 1; \
fi
@mkdir -p logs
@rm -f logs/pipe
@mkfifo logs/pipe
@cat logs/pipe | (make start-backend) &
@echo 'test' | tee logs/pipe | (make start-frontend)
@poetry run nohup uvicorn opendevin.server.listen:app --port $(BACKEND_PORT) > logs/backend_$(shell date +'%Y%m%d_%H%M%S').log 2>&1 &
@echo "Waiting for the backend to start..."
@until nc -z localhost $(BACKEND_PORT); do sleep 0.1; done
@cd frontend && pnpm run start -- --port $(FRONTEND_PORT)
# Setup config.toml
setup-config:
@echo "Setting up config.toml..."
@read -p "Enter your LLM Model name (see docs.litellm.ai/docs/providers for full list) [default: $(DEFAULT_MODEL)]: " llm_model; \
@read -p "Enter your LLM Model name (see https://docs.litellm.ai/docs/providers for full list) [default: $(DEFAULT_MODEL)]: " llm_model; \
llm_model=$${llm_model:-$(DEFAULT_MODEL)}; \
echo "LLM_MODEL=\"$$llm_model\"" >> $(CONFIG_FILE).tmp
echo "LLM_MODEL=\"$$llm_model\"" > $(CONFIG_FILE).tmp
@read -p "Enter your LLM API key: " llm_api_key; \
echo "LLM_API_KEY=\"$$llm_api_key\"" >> $(CONFIG_FILE).tmp
@@ -86,6 +90,7 @@ help:
@echo "Usage: make [target]"
@echo "Targets:"
@echo " build - Build project, including environment setup and dependencies."
@echo " build-eval - Build project evaluation pipeline, including environment setup and dependencies."
@echo " start-backend - Start the backend server for the OpenDevin project."
@echo " start-frontend - Start the frontend server for the OpenDevin project."
@echo " run - Run the OpenDevin application, starting both backend and frontend servers."
@@ -94,4 +99,4 @@ help:
@echo " help - Display this help message, providing information on available targets."
# Phony targets
.PHONY: install start-backend start-frontend run setup-config help
.PHONY: build build-eval start-backend start-frontend run setup-config help
-32
View File
@@ -1,32 +0,0 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
datasets = "*"
pandas = "*"
litellm = "*"
termcolor = "*"
seaborn = "*"
docker = "*"
fastapi = "*"
uvicorn = {extras = ["standard"], version = "*"}
ruff = "*"
mypy = "*"
llama-index = "*"
llama-index-vector-stores-chroma = "*"
chromadb = "*"
llama-index-embeddings-huggingface = "*"
llama-index-embeddings-azure-openai = "*"
llama-index-embeddings-ollama = "*"
google-generativeai = "*"
toml = "*"
json_repair = "*"
numpy = "*"
playwright = "*"
[dev-packages]
[requires]
python_version = "3.11"
Generated
-3854
View File
File diff suppressed because it is too large Load Diff
-38
View File
@@ -1,38 +0,0 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[[source]]
url = "https://download.pytorch.org/whl/cpu"
verify_ssl = true
name = "pytorch"
[packages]
torch = {version = "*", index = "pytorch"}
datasets = "*"
pandas = "*"
litellm = "*"
termcolor = "*"
seaborn = "*"
docker = "*"
fastapi = "*"
uvicorn = {extras = ["standard"], version = "*"}
ruff = "*"
mypy = "*"
llama-index = "*"
llama-index-vector-stores-chroma = "*"
chromadb = "*"
llama-index-embeddings-huggingface = "*"
llama-index-embeddings-azure-openai = "*"
llama-index-embeddings-ollama = "*"
google-generativeai = "*"
toml = "*"
json_repair = "*"
numpy = "*"
playwright = "*"
[dev-packages]
[requires]
python_version = "3.11"
+4 -4
View File
@@ -18,9 +18,9 @@ You're a thoughtful robot. Your main task is this:
Don't expand the scope of your task--just complete it as written.
This is your internal monologue, in JSON format:
```json
%(monologue)s
```
Your most recent thought is at the bottom of that monologue. Continue your train of thought.
What is your next thought or action? Your response must be in JSON format.
@@ -71,9 +71,9 @@ Please return a new, smaller JSON array, which summarizes the
internal monologue. You can summarize individual thoughts, and
you can condense related thoughts together with a description
of their content.
```json
%(monologue)s
```
Make the summaries as pithy and informative as possible.
Be specific about what happened and what was learned. The summary
will be used as keywords for searching for the original memory.
+5 -5
View File
@@ -53,9 +53,9 @@ You've been given the following task:
## 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:
```json
%(plan)s
```
%(plan_status)s
@@ -84,9 +84,9 @@ you MUST respond with the `finish` action.
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.
```json
%(history)s
```
Your most recent action is at the bottom of that history.
@@ -118,7 +118,7 @@ It must be an object, and it must contain two fields:
* `modify_task` - close a task. Arguments:
* `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 abanded, and you're absolutely certain that you've completed your task and have tested your work, use the finish action to stop working.
* `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.
You should never act twice in a row without thinking. But if your last several
+1 -1
View File
@@ -8,4 +8,4 @@ warn_redundant_casts = True
no_implicit_optional = True
strict_optional = True
exclude = agenthub/monologue_agent/regression
exclude = agenthub/monologue_agent/regression
+683 -957
View File
File diff suppressed because it is too large Load Diff
+33 -7
View File
@@ -1,10 +1,29 @@
import React, { useState } from "react";
import "./App.css";
import CogTooth from "./assets/cog-tooth";
import ChatInterface from "./components/ChatInterface";
import Errors from "./components/Errors";
import SettingModal from "./components/SettingModal";
import Terminal from "./components/Terminal";
import Workspace from "./components/Workspace";
interface Props {
setSettingOpen: (isOpen: boolean) => void;
}
function LeftNav({ setSettingOpen }: Props): JSX.Element {
return (
<div className="flex flex-col h-full p-4 bg-bg-dark w-16 items-center shrink-0">
<div
className="mt-auto cursor-pointer hover:opacity-80"
onClick={() => setSettingOpen(true)}
>
<CogTooth />
</div>
</div>
);
}
function App(): JSX.Element {
const [settingOpen, setSettingOpen] = useState(false);
@@ -14,15 +33,22 @@ function App(): JSX.Element {
return (
<div className="flex h-screen bg-bg-dark text-white">
<Errors />
<div className="flex-1 rounded-xl m-4 overflow-hidden bg-bg-light">
<ChatInterface setSettingOpen={setSettingOpen} />
<LeftNav setSettingOpen={setSettingOpen} />
<div className="flex flex-col grow gap-3 py-3 pr-3">
<div className="flex gap-3 grow">
<div className="w-[500px] shrink-0 rounded-xl overflow-hidden border border-border">
<ChatInterface />
</div>
<div className="flex flex-col flex-1 overflow-hidden rounded-xl bg-bg-workspace border border-border">
<Workspace />
</div>
</div>
<div className="h-72 shrink-0 bg-bg-workspace rounded-xl border border-border flex flex-col">
<Terminal key="terminal" />
</div>
</div>
<div className="flex flex-col flex-1 m-4 overflow-hidden rounded-xl bg-bg-light">
<Workspace />
</div>
<SettingModal isOpen={settingOpen} onClose={handleCloseModal} />
<Errors />
</div>
);
}
+7 -20
View File
@@ -1,21 +1,20 @@
import { Card, CardBody } from "@nextui-org/react";
import React, { useEffect, useRef } from "react";
import { useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import assistantAvatar from "../assets/assistant-avatar.png";
import CogTooth from "../assets/cog-tooth";
import userAvatar from "../assets/user-avatar.png";
import { useTypingEffect } from "../hooks/useTypingEffect";
import { I18nKey } from "../i18n/declaration";
import {
addAssistantMessageToChat,
setCurrentQueueMarkerState,
setCurrentTypingMsgState,
setTypingAcitve,
addAssistantMessageToChat,
} from "../services/chatService";
import { RootState } from "../store";
import { Message } from "../state/chatSlice";
import { RootState } from "../store";
import Input from "./Input";
import { I18nKey } from "../i18n/declaration";
interface IChatBubbleProps {
msg: Message;
@@ -185,24 +184,12 @@ function InitializingStatus(): JSX.Element {
);
}
interface Props {
setSettingOpen: (isOpen: boolean) => void;
}
function ChatInterface({ setSettingOpen }: Props): JSX.Element {
function ChatInterface(): JSX.Element {
const { initialized } = useSelector((state: RootState) => state.task);
return (
<div className="flex flex-col h-full p-0 bg-bg-light">
<div className="w-full flex justify-between p-5">
<div />
<div
className="cursor-pointer hover:opacity-80"
onClick={() => setSettingOpen(true)}
>
<CogTooth />
</div>
</div>
<div className="flex flex-col h-full p-0 bg-bg-workspace">
<div className="border-b border-border text-lg px-4 py-2">Chat</div>
{initialized ? <MessageList /> : <InitializingStatus />}
<Input />
</div>
+10 -3
View File
@@ -1,7 +1,7 @@
import React, { useEffect, useRef } from "react";
import { IDisposable, Terminal as XtermTerminal } from "@xterm/xterm";
import { FitAddon } from "xterm-addon-fit";
import "@xterm/xterm/css/xterm.css";
import React, { useEffect, useRef } from "react";
import { FitAddon } from "xterm-addon-fit";
import socket from "../socket/socket";
class JsonWebsocketAddon {
@@ -88,7 +88,14 @@ function Terminal(): JSX.Element {
};
}, []);
return <div ref={terminalRef} className="h-full w-full block" />;
return (
<div className="flex flex-col h-full">
<div className="px-4 py-2 text-lg border-b border-border">Terminal</div>
<div className="grow p-2 flex min-h-0">
<div ref={terminalRef} className="h-full w-full" />
</div>
</div>
);
}
export default Terminal;
+11 -18
View File
@@ -1,28 +1,21 @@
import React, { useMemo, useState } from "react";
import { Tab, Tabs } from "@nextui-org/react";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import Terminal from "./Terminal";
import Planner from "./Planner";
import CodeEditor from "./CodeEditor";
import Browser from "./Browser";
import { TabType, TabOption, AllTabs } from "../types/TabOption";
import CmdLine from "../assets/cmd-line";
import Calendar from "../assets/calendar";
import Earth from "../assets/earth";
import Pencil from "../assets/pencil";
import { I18nKey } from "../i18n/declaration";
import { AllTabs, TabOption, TabType } from "../types/TabOption";
import Browser from "./Browser";
import CodeEditor from "./CodeEditor";
import Planner from "./Planner";
function Workspace() {
const { t } = useTranslation();
const [activeTab, setActiveTab] = useState<TabType>(TabOption.TERMINAL);
const [activeTab, setActiveTab] = useState<TabType>(TabOption.CODE);
const tabData = useMemo(
() => ({
[TabOption.TERMINAL]: {
name: t(I18nKey.WORKSPACE$TERMINAL_TAB_LABEL),
icon: <CmdLine />,
component: <Terminal key="terminal" />,
},
[TabOption.PLANNER]: {
name: t(I18nKey.WORKSPACE$PLANNER_TAB_LABEL),
icon: <Calendar />,
@@ -44,12 +37,12 @@ function Workspace() {
return (
<>
<div className="w-full p-4 text-2xl font-bold select-none">
{t(I18nKey.WORKSPACE$TITLE)}
</div>
<div role="tablist" className="tabs tabs-bordered tabs-lg ">
<div
role="tablist"
className="tabs tabs-bordered tabs-lg border-b border-border"
>
<Tabs
variant="underlined"
variant="light"
size="lg"
onSelectionChange={(v) => {
setActiveTab(v as TabType);
+6 -6
View File
@@ -1,22 +1,22 @@
:root {
--bg-dark: #1e1e1e;
--bg-dark: #0c0e10;
--bg-light: #292929;
--bg-input: #393939;
--bg-workspace: #171717;
--bg-workspace: #1f2228;
--border: #3c3c4a;
background-color: var(--bg-dark) !important;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
+2 -12
View File
@@ -1,21 +1,11 @@
enum TabOption {
TERMINAL = "terminal",
PLANNER = "planner",
CODE = "code",
BROWSER = "browser",
}
type TabType =
| TabOption.TERMINAL
| TabOption.PLANNER
| TabOption.CODE
| TabOption.BROWSER;
type TabType = TabOption.PLANNER | TabOption.CODE | TabOption.BROWSER;
const AllTabs = [
TabOption.TERMINAL,
TabOption.PLANNER,
TabOption.CODE,
TabOption.BROWSER,
];
const AllTabs = [TabOption.PLANNER, TabOption.CODE, TabOption.BROWSER];
export { AllTabs, TabOption, type TabType };
+14 -12
View File
@@ -1,23 +1,25 @@
/** @type {import('tailwindcss').Config} */
const {nextui} = require("@nextui-org/react");
const { nextui } = require("@nextui-org/react");
export default {
content: [
'./src/**/*.{js,ts,jsx,tsx}',
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
"./src/**/*.{js,ts,jsx,tsx}",
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
'bg-dark': 'var(--bg-dark)',
'bg-light': 'var(--bg-light)',
'bg-input': 'var(--bg-input)',
'bg-workspace': 'var(--bg-workspace)'
"bg-dark": "var(--bg-dark)",
"bg-light": "var(--bg-light)",
"bg-input": "var(--bg-input)",
"bg-workspace": "var(--bg-workspace)",
border: "var(--border)",
},
},
},
darkMode: "class",
plugins: [nextui({
defaultTheme: "dark"
})],
}
plugins: [
nextui({
defaultTheme: "dark",
}),
],
};
+5 -1
View File
@@ -1,5 +1,5 @@
import os
import toml
import toml # type: ignore
from dotenv import load_dotenv
@@ -34,12 +34,14 @@ for key, value in config.items():
config[key] = tomlConfig[key]
def _get(key: str, default):
value = config.get(key, default)
if not value:
value = os.environ.get(key, default)
return value
def get_or_error(key: str):
"""
Get a key from the config, or raise an error if it doesn't exist.
@@ -49,12 +51,14 @@ def get_or_error(key: str):
raise KeyError(f"Please set '{key}' in `config.toml` or `.env`.")
return value
def get_or_default(key: str, default):
"""
Get a key from the config, or return a default value if it doesn't exist.
"""
return _get(key, default)
def get_or_none(key: str):
"""
Get a key from the config, or return None if it doesn't exist.
+6 -3
View File
@@ -1,8 +1,8 @@
from opendevin.server.session import Session
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
import agenthub # noqa F401 (we import this to get the agents registered)
import litellm
import agenthub # noqa F401 (we import this to get the agents registered)
import litellm
from opendevin.agent import Agent
from opendevin import config
@@ -16,6 +16,7 @@ app.add_middleware(
allow_headers=["*"],
)
# This endpoint receives events from the client (i.e. the browser)
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
@@ -24,12 +25,14 @@ async def websocket_endpoint(websocket: WebSocket):
# TODO: should this use asyncio instead of await?
await session.start_listening()
@app.get("/litellm-models")
async def get_litellm_models():
"""
Get all models supported by LiteLLM.
"""
return litellm.model_list
return list(set(litellm.model_list + list(litellm.model_cost.keys())))
@app.get("/litellm-agents")
async def get_litellm_agents():
Generated
+5814
View File
File diff suppressed because it is too large Load Diff
+48
View File
@@ -0,0 +1,48 @@
[tool.poetry]
name = "opendevin"
version = "0.1.0"
description = "OpenDevin: Code Less, Make More"
authors = ["OpenDevin"]
license = "MIT"
readme = "README.md"
repository = "https://github.com/OpenDevin/OpenDevin"
[tool.poetry.dependencies]
python = "^3.11"
datasets = "*"
pandas = "*"
litellm = "*"
termcolor = "*"
seaborn = "*"
docker = "*"
fastapi = "*"
toml = "*"
uvicorn = "*"
types-toml = "*"
numpy = "*"
json-repair = "*"
playwright = "*"
[tool.poetry.group.llama-index.dependencies]
llama-index = "*"
llama-index-vector-stores-chroma = "*"
chromadb = "*"
llama-index-embeddings-huggingface = "*"
llama-index-embeddings-azure-openai = "*"
llama-index-embeddings-ollama = "*"
pymupdfb = "*"
[tool.poetry.group.dev.dependencies]
ruff = "*"
mypy = "*"
pre-commit = "*"
[tool.poetry.group.test.dependencies]
pytest = "*"
[tool.poetry.group.evaluation.dependencies]
torch = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"