Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

code viewer, layout save, toast color #451

Merged
merged 10 commits into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 10 additions & 3 deletions devika.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ def handle_message(data):
emit_agent("info", {"type": "warning", "message": "previous agent doesn't completed it's task."})
last_state = AgentState.get_latest_state(project_name)
if last_state["agent_is_active"] or not last_state["completed"]:
# emit_agent("info", {"type": "info", "message": "I'm trying to complete the previous task again."})
# message = manager.get_latest_message_from_user(project_name)
thread = Thread(target=lambda: agent.execute(message, project_name))
thread.start()
else:
Expand All @@ -118,6 +116,14 @@ def get_agent_state():
return jsonify({"state": agent_state})


@app.route("/api/get-project-files/", methods=["GET"])
@route_logger(logger)
def project_files():
project_name = request.args.get("project_name")
files = AgentState.get_project_files(project_name)
return jsonify({"files": files})


@app.route("/api/get-browser-snapshot", methods=["GET"])
@route_logger(logger)
def browser_snapshot():
Expand Down Expand Up @@ -198,8 +204,9 @@ def get_settings():


@app.route("/api/status", methods=["GET"])
@route_logger(logger)
def status():
return jsonify({"status": "server is running!"}), 200
return jsonify({"status": "server is running!"})

if __name__ == "__main__":
logger.info("Devika is up and running!")
Expand Down
10 changes: 10 additions & 0 deletions src/agents/coder/coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from src.state import AgentState
from src.logger import Logger
from src.services.utils import retry_wrapper
from src.socket_instance import emit_agent

PROMPT = open("src/agents/coder/prompt.jinja2", "r").read().strip()

Expand Down Expand Up @@ -87,6 +88,7 @@ def response_to_markdown_prompt(self, response: List[Dict[str, str]]) -> str:
return f"~~~\n{response}\n~~~"

def emulate_code_writing(self, code_set: list, project_name: str):
files = []
for current_file in code_set:
file = current_file["file"]
code = current_file["code"]
Expand All @@ -98,8 +100,16 @@ def emulate_code_writing(self, code_set: list, project_name: str):
new_state["terminal_session"]["title"] = f"Editing {file}"
new_state["terminal_session"]["command"] = f"vim {file}"
new_state["terminal_session"]["output"] = code
files.append({
"file": file,
"code": code
})
AgentState().add_to_current_state(project_name, new_state)
time.sleep(2)
emit_agent("code", {
"files": files,
"from": "coder"
})

@retry_wrapper
def execute(
Expand Down
10 changes: 10 additions & 0 deletions src/agents/feature/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from src.llm import LLM
from src.state import AgentState
from src.services.utils import retry_wrapper
from src.socket_instance import emit_agent

PROMPT = open("src/agents/feature/prompt.jinja2", "r").read().strip()

Expand Down Expand Up @@ -85,6 +86,7 @@ def response_to_markdown_prompt(self, response: List[Dict[str, str]]) -> str:
return f"~~~\n{response}\n~~~"

def emulate_code_writing(self, code_set: list, project_name: str):
files = []
for file in code_set:
filename = file["file"]
code = file["code"]
Expand All @@ -94,8 +96,16 @@ def emulate_code_writing(self, code_set: list, project_name: str):
new_state["terminal_session"]["title"] = f"Editing {filename}"
new_state["terminal_session"]["command"] = f"vim {filename}"
new_state["terminal_session"]["output"] = code
files.append({
"file": filename,
"code": code,
})
AgentState().add_to_current_state(project_name, new_state)
time.sleep(1)
emit_agent("code", {
"files": files,
"from": "feature"
})

@retry_wrapper
def execute(
Expand Down
10 changes: 10 additions & 0 deletions src/agents/patcher/patcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from jinja2 import Environment, BaseLoader
from typing import List, Dict, Union
from src.socket_instance import emit_agent

from src.config import Config
from src.llm import LLM
Expand Down Expand Up @@ -87,6 +88,7 @@ def response_to_markdown_prompt(self, response: List[Dict[str, str]]) -> str:
return f"~~~\n{response}\n~~~"

def emulate_code_writing(self, code_set: list, project_name: str):
files = []
for current_file in code_set:
file = current_file["file"]
code = current_file["code"]
Expand All @@ -96,8 +98,16 @@ def emulate_code_writing(self, code_set: list, project_name: str):
new_state["terminal_session"]["title"] = f"Editing {file}"
new_state["terminal_session"]["command"] = f"vim {file}"
new_state["terminal_session"]["output"] = code
files.append({
"file": file,
"code": code
})
AgentState().add_to_current_state(project_name, new_state)
time.sleep(1)
emit_agent("code", {
"files": files,
"from": "patcher"
})

@retry_wrapper
def execute(
Expand Down
26 changes: 26 additions & 0 deletions src/state.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import os
from datetime import datetime
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine
Expand Down Expand Up @@ -173,3 +174,28 @@ def get_latest_token_usage(self, project: str):
if agent_state:
return json.loads(agent_state.state_stack_json)[-1]["token_usage"]
return 0

def get_project_files(self, project_name: str):
if not project_name:
return []
project_directory = "-".join(project_name.split(" "))
directory = os.path.join(os.getcwd(), 'data', 'projects', project_directory)
if(not os.path.exists(directory)):
return []
files = []
for root, _, filenames in os.walk(directory):
for filename in filenames:
file_relative_path = os.path.relpath(root, directory)
if file_relative_path == '.': file_relative_path = ''
file_path = os.path.join(file_relative_path, filename)
print("file_path",file_path)
try:
with open(os.path.join(root, filename), 'r') as file:
print("File:", filename)
files.append({
"file": file_path,
"code": file.read()
})
except Exception as e:
print(f"Error reading file {filename}: {e}")
return files
Binary file modified ui/bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
"preview": "vite preview"
},
"devDependencies": {
"@monaco-editor/loader": "^1.4.0",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.2",
"autoprefixer": "^10.4.16",
"monaco-editor": "^0.48.0",
"postcss": "^8.4.32",
"postcss-load-config": "^5.0.2",
"svelte": "^4.2.7",
Expand Down
1 change: 1 addition & 0 deletions ui/src/app.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
/* WebKit (Chrome, Safari) */
*::-webkit-scrollbar {
width: 5px;
height: 2px
}
*::-webkit-scrollbar-thumb {
background: #999797;
Expand Down
9 changes: 9 additions & 0 deletions ui/src/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
modelList,
projectList,
messages,
projectFiles,
searchEngineList,
} from "./store";
import { io } from "socket.io-client";
Expand Down Expand Up @@ -125,6 +126,14 @@ export async function getBrowserSnapshot(snapshotPath) {
return data.snapshot;
}

export async function fetchProjectFiles() {
const projectName = localStorage.getItem("selectedProject");
const response = await fetch(`${API_BASE_URL}/api/get-project-files?project_name=${projectName}`)
const data = await response.json();
projectFiles.set(data.files);
return data.files;
}

export async function checkInternetStatus() {
if (navigator.onLine) {
internet.set(true);
Expand Down
3 changes: 2 additions & 1 deletion ui/src/lib/components/ControlPanel.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<script>
import { onMount } from "svelte";
import { projectList, modelList, internet, tokenUsage, agentState, messages, searchEngineList, serverStatus, isSending, selectedProject, selectedModel, selectedSearchEngine} from "$lib/store";
import { createProject, fetchMessages, fetchInitialData, deleteProject, fetchAgentState} from "$lib/api";
import { createProject, fetchMessages, fetchInitialData, deleteProject,fetchProjectFiles, fetchAgentState} from "$lib/api";
import Seperator from "./ui/Seperator.svelte";

function selectProject(project) {
$selectedProject = project;
fetchMessages();
fetchAgentState();
fetchProjectFiles();
document.getElementById("project-dropdown").classList.add("hidden");
}
function selectModel(model) {
Expand Down
99 changes: 99 additions & 0 deletions ui/src/lib/components/EditorWidget.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<script>
import { onDestroy, onMount } from 'svelte';
import { initializeMonaco, initializeEditorRef, createModel, disposeEditor, enableTabSwitching, sidebar } from './MonacoEditor';
import { socket } from "$lib/api";
import { projectFiles } from "$lib/store";

let monaco;
let models = {};
let editor = null;
let editorContainer;
let tabContainer;
let sidebarContainer;

const reCreateEditor = async (files) => {
disposeEditor(editor);
models = {};
editor = await initializeEditorRef(monaco, editorContainer)
files.forEach((file) => {
let model = createModel(monaco, file);
editor.setModel(model);
models = {
...models,
[file.file]: model
};
});
enableTabSwitching(editor, models, tabContainer);
sidebar(editor, models, sidebarContainer);
};

const patchOrFeature = (files) => {
files.forEach((file, index) => {
const model = models[file.file];
if (model) {
model.setValue(file.code);
}else {
let model = createModel(monaco, file);
models = {
...models,
[file.file]: model
};
}
});
enableTabSwitching(editor, models, tabContainer);
sidebar(editor, models, sidebarContainer);
};

const initializeEditor = async () => {
monaco = await initializeMonaco();
// const files = await fetchProjectFiles();
// reCreateEditor(files)
};

onMount(async () => {
await initializeEditor()
socket.on('code', async function (data) {
if(data.from === 'coder'){
reCreateEditor(data.files);
}else{
patchOrFeature(data.files)
}
});

projectFiles.subscribe((files) => {
if (files){
reCreateEditor(files);
}
});
});

onDestroy(() => {
disposeEditor(editor);
models = {};
});

// $: if ($selectedProject && $selectedProject != 'select project') {
// initializeEditor()
// }
</script>


<div
class="w-full h-full flex flex-1 flex-col border-[3px] overflow-hidden rounded-xl border-window-outline p-0"
>
<div class="flex items-center p-2 border-b bg-terminal-window-ribbon">
<div class="flex ml-2 mr-4 space-x-2">
<div class="w-3 h-3 rounded-full bg-terminal-window-dots"></div>
<div class="w-3 h-3 rounded-full bg-terminal-window-dots"></div>
<div class="w-3 h-3 rounded-full bg-terminal-window-dots"></div>
</div>
<div id="tabContainer" class="flex text-tertiary text-sm overflow-x-auto" bind:this={tabContainer} />
{#if Object.keys(models).length == 0}
<div class="flex items-center text-tertiary text-sm">Code viewer</div>
{/if}
</div>
<div class="h-full w-full flex">
<div class="min-w-[260px] overflow-y-auto bg-secondary h-full text-foreground text-sm flex flex-col pt-2" bind:this={sidebarContainer} />
<div class="h-full w-full rounded-bl-lg bg-terminal-window-background p-0" bind:this={editorContainer} />
</div>
</div>
6 changes: 0 additions & 6 deletions ui/src/lib/components/MessageInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@
project_name: projectName,
search_engine: serachEngine,
});
console.log({
message: messageInput,
base_model: selectedModel,
project_name: projectName,
search_engine: serachEngine,
});
messageInput = "";

}
Expand Down