Skip to content

Commit

Permalink
all functions async, fix automode iterations showing in ui, improve p…
Browse files Browse the repository at this point in the history
…roject state, sync system
  • Loading branch information
bigsk1 committed Jul 29, 2024
1 parent cac04f0 commit a1ca118
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 133 deletions.
14 changes: 8 additions & 6 deletions automode_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
# You should have received a copy of the GNU General Public License
# along with Claude Plus. If not, see <https://www.gnu.org/licenses/>.
import os
import asyncio
import json
import logging
from typing import Generator
from typing import AsyncGenerator
from pydantic import BaseModel
from fastapi import HTTPException
from config import CLAUDE_MODEL, anthropic_client
Expand All @@ -36,14 +37,14 @@
class AutomodeRequest(BaseModel):
message: str

def start_automode_logic(request: AutomodeRequest) -> Generator[str, None, None]:
async def start_automode_logic(request: AutomodeRequest) -> AsyncGenerator[str, None]:
global automode_progress, automode_messages, project_state
try:
automode_progress = 0
automode_messages = []

# Synchronize project state at the start
sync_project_state_with_fs()
await sync_project_state_with_fs()
logger.debug(f"Initial project state: {project_state}")

system_message = f"""
Expand Down Expand Up @@ -112,26 +113,27 @@ def start_automode_logic(request: AutomodeRequest) -> Generator[str, None, None]
tool_name = content.name
tool_input = content.input
logger.debug(f"Using tool: {tool_name} with input: {tool_input}")
tool_result = execute_tool(tool_name, tool_input)
tool_result = await execute_tool(tool_name, tool_input)
assistant_response += f"Used tool: {tool_name}\nResult: {tool_result}\n\n"
# Log and save project state after each tool use
logger.debug(f"Project state after {tool_name}: {project_state}")
save_state_to_file(project_state)
await save_state_to_file(project_state)

automode_messages.append({"role": "assistant", "content": assistant_response})
automode_progress = (i + 1) / MAX_ITERATIONS * 100

logger.debug(f"Progress: {automode_progress}, Messages: {automode_messages}")

yield f"data: {json.dumps({'event': 'message', 'content': assistant_response})}\n\n"
await asyncio.sleep(0.1) # Add a small delay to ensure the event is sent

if "AUTOMODE_COMPLETE" in assistant_response:
break

conversation_history.append({"role": "assistant", "content": assistant_response})
conversation_history.append({"role": "user", "content": "Continue with the next step if necessary or reply with AUTOMODE_COMPLETE if finished."})

sync_project_state_with_fs()
await sync_project_state_with_fs()
logger.debug(f"Project state after syncing: {project_state}")


Expand Down
155 changes: 84 additions & 71 deletions backend.py

Large diffs are not rendered by default.

25 changes: 17 additions & 8 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ function App() {
const toast = useToast();

useEffect(() => {
listFiles(currentDirectory);
(async () => {
await listFiles(currentDirectory);
})();
}, [currentDirectory]);

useEffect(() => {
Expand Down Expand Up @@ -143,35 +145,41 @@ function App() {
setIsAutoMode(true);
setAutomodeProgress(0);
setMessages(prev => [...prev, { role: 'user', content: input }]);
setInput(''); // Clear input field

setInput('');
console.log("Starting automode");
const eventSource = new EventSource(`${API_URL}/automode?message=${encodeURIComponent(input)}`);

eventSource.onmessage = (event) => {
console.log("Received SSE event:", event);
const data = JSON.parse(event.data);
console.log("Parsed event data:", data);
if (data.event === 'message') {
console.log("Updating messages with new content");
setMessages(prev => [...prev, { role: 'assistant', content: data.content }]);
setAutomodeProgress(prev => Math.min(prev + 20, 100)); // Example progress update
setAutomodeProgress(prev => {
const newProgress = Math.min(prev + 20, 100);
console.log("Updating progress:", newProgress);
return newProgress;
});
} else if (data.event === 'end') {
console.log("Automode completed");
setAutomodeProgress(100);
eventSource.close();
setIsAutoMode(false);
} else if (data.event === 'error') {
console.error("Automode error:", data.content);
setMessages(prev => [...prev, { role: 'system', content: data.content }]);
eventSource.close();
setIsAutoMode(false);
}
};

eventSource.onerror = (error) => {
console.error('Error in automode:', error);
setMessages(prev => [...prev, { role: 'system', content: 'Error: Automode failed' }]);
eventSource.close();
setIsAutoMode(false);
};

// Cleanup on component unmount
return () => {
console.log("Cleaning up automode");
eventSource.close();
};
} catch (error) {
Expand Down Expand Up @@ -240,6 +248,7 @@ function App() {
setFiles([]);
}
};


const createFolder = async () => {
const folderName = prompt('Enter folder name:');
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/Console.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ const Console: React.FC = () => {
const terminalRef = useRef<HTMLDivElement>(null);

useEffect(() => {
fetchCurrentDirectory();
(async () => {
await fetchCurrentDirectory();
})();
}, []);

useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion project_state.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"folders": ["uploads", "my_website"], "files": ["my_website/index.html", "hey.txt"]}
{"folders": ["uploads", "test_project"], "files": ["test_project/index.html", "test_project/styles.css"]}
29 changes: 16 additions & 13 deletions project_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import json
from config import PROJECTS_DIR


logger = logging.getLogger(__name__)

PROJECT_STATE_FILE = "project_state.json"
Expand All @@ -14,7 +13,7 @@
"files": set()
}

def clear_state_file():
async def clear_state_file():
global project_state
project_state = {"folders": set(), "files": set()}
try:
Expand All @@ -25,38 +24,42 @@ def clear_state_file():
logger.error(f"Error clearing project state file: {str(e)}")
return project_state

def sync_project_state_with_fs():
async def sync_project_state_with_fs():
global project_state
project_state = {"folders": set(), "files": set()}
new_state = {"folders": set(), "files": set()}

for root, dirs, files in os.walk(PROJECTS_DIR):
for dir in dirs:
rel_path = os.path.relpath(os.path.join(root, dir), PROJECTS_DIR).replace(os.sep, '/')
project_state["folders"].add(rel_path)
new_state["folders"].add(rel_path)
for file in files:
rel_path = os.path.relpath(os.path.join(root, file), PROJECTS_DIR).replace(os.sep, '/')
project_state["files"].add(rel_path)
new_state["files"].add(rel_path)

save_state_to_file(project_state)
project_state = new_state
await save_state_to_file(project_state)
logger.debug(f"Synced project state with file system: {project_state}")
return project_state

def save_state_to_file(state, filename=PROJECT_STATE_FILE):
async def save_state_to_file(state, filename=PROJECT_STATE_FILE):
with open(filename, 'w') as f:
json.dump({"folders": list(state["folders"]), "files": list(state["files"])}, f)
logger.debug(f"Saved project state to file: {state}")

def load_state_from_file(filename=PROJECT_STATE_FILE):
async def load_state_from_file(filename=PROJECT_STATE_FILE):
try:
with open(filename, 'r') as f:
data = json.load(f)
return {"folders": set(data["folders"]), "files": set(data["files"])}
except FileNotFoundError:
return {"folders": set(), "files": set()}

# Load the state at the beginning
project_state = load_state_from_file()
async def initialize_project_state():
global project_state
project_state = await load_state_from_file()
logger.info("Project state initialized")

def refresh_project_state():
async def refresh_project_state():
global project_state
project_state = {"folders": set(), "files": set()}

Expand All @@ -66,4 +69,4 @@ def refresh_project_state():
for file_name in files:
project_state["files"].add(os.path.relpath(os.path.join(root, file_name), PROJECTS_DIR).replace('\\', '/'))

save_state_to_file(project_state)
await save_state_to_file(project_state)
Loading

0 comments on commit a1ca118

Please sign in to comment.