Skip to content

Commit

Permalink
Merge pull request #17 from dougollerenshaw/add_tests
Browse files Browse the repository at this point in the history
Add GitHub Actions workflow for running tests
  • Loading branch information
dougollerenshaw authored Sep 19, 2024
2 parents 1fd8001 + d511815 commit ee2dde5
Show file tree
Hide file tree
Showing 22 changed files with 764 additions and 222 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/black.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Black Code Formatter

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: psf/black@stable
with:
options: "--check --verbose"
src: "./codeaide"
- name: If needed, commit black changes to the pull request
if: failure()
run: |
black ./codeaide
git config --global user.name github-actions
git config --global user.email [email protected]
git commit -am "Auto-format code with black"
git push
31 changes: 31 additions & 0 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Python Tests

on:
push:
branches: [ main, add_tests ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9, '3.10']

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-mock
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Run tests
env:
ANTHROPIC_API_KEY: dummy_key_for_testing
run: |
pytest -v
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
repos:
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
language_version: python3
9 changes: 7 additions & 2 deletions codeaide.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import sys

from PyQt5.QtWidgets import QApplication

from codeaide.logic.chat_handler import ChatHandler
from codeaide.ui.chat_window import ChatWindow
from codeaide.utils import api_utils


def main():
chat_handler = ChatHandler()

if len(sys.argv) > 1 and sys.argv[1] == 'test':
if len(sys.argv) > 1 and sys.argv[1] == "test":
success, message = chat_handler.check_api_connection()
success, message = api_utils.test_api_connection()
if success:
print("Connection successful!")
Expand All @@ -21,5 +25,6 @@ def main():
chat_window.show()
sys.exit(app.exec_())


if __name__ == "__main__":
main()
main()
110 changes: 76 additions & 34 deletions codeaide/logic/chat_handler.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from codeaide.utils.api_utils import send_api_request, parse_response
import json
import os

from codeaide.utils.api_utils import parse_response, send_api_request
from codeaide.utils.constants import MAX_RETRIES, MAX_TOKENS
from codeaide.utils.cost_tracker import CostTracker
from codeaide.utils.environment_manager import EnvironmentManager
from codeaide.utils.terminal_manager import TerminalManager
from codeaide.utils.file_handler import FileHandler
from codeaide.utils.cost_tracker import CostTracker
from codeaide.utils.constants import MAX_TOKENS, MAX_RETRIES
import os
import json
from codeaide.utils.terminal_manager import TerminalManager


class ChatHandler:
def __init__(self):
Expand All @@ -20,66 +22,106 @@ def __init__(self):
def process_input(self, user_input):
try:
self.conversation_history.append({"role": "user", "content": user_input})

for attempt in range(MAX_RETRIES):
version_info = f"\n\nThe latest code version was {self.latest_version}. If you're making minor changes to the previous code, increment the minor version (e.g., 1.0 to 1.1). If you're creating entirely new code, increment the major version (e.g., 1.1 to 2.0). Ensure the new version is higher than {self.latest_version}."
self.conversation_history[-1]["content"] += version_info

response = send_api_request(self.conversation_history, MAX_TOKENS)
print(f"Response (Attempt {attempt + 1}): {response}")

if response is None:
if attempt == MAX_RETRIES - 1:
return {'type': 'error', 'message': "Failed to get a response from the AI. Please try again."}
return {
"type": "error",
"message": "Failed to get a response from the AI. Please try again.",
}
continue

self.cost_tracker.log_request(response)

try:
text, questions, code, code_version, version_description, requirements = parse_response(response)

if code and self.compare_versions(code_version, self.latest_version) <= 0:
raise ValueError(f"New version {code_version} is not higher than the latest version {self.latest_version}")

(
text,
questions,
code,
code_version,
version_description,
requirements,
) = parse_response(response)

if (
code
and self.compare_versions(code_version, self.latest_version)
<= 0
):
raise ValueError(
f"New version {code_version} is not higher than the latest version {self.latest_version}"
)

if code:
self.latest_version = code_version
self.conversation_history.append({"role": "assistant", "content": response.content[0].text})

self.conversation_history.append(
{"role": "assistant", "content": response.content[0].text}
)

if questions:
return {'type': 'questions', 'message': text, 'questions': questions}
return {
"type": "questions",
"message": text,
"questions": questions,
}
elif code:
self.file_handler.save_code(code, code_version, version_description, requirements)
return {'type': 'code', 'message': f"{text}\n\nOpening in the code window as v{code_version}...", 'code': code, 'requirements': requirements}
self.file_handler.save_code(
code, code_version, version_description, requirements
)
return {
"type": "code",
"message": f"{text}\n\nOpening in the code window as v{code_version}...",
"code": code,
"requirements": requirements,
}
else:
return {'type': 'message', 'message': text}
return {"type": "message", "message": text}

except (json.JSONDecodeError, ValueError) as e:
print(f"Error processing response (Attempt {attempt + 1}): {e}")
if attempt < MAX_RETRIES - 1:
error_prompt = f"\n\nThere was an error in your response: {e}. Please ensure you're using proper JSON formatting and incrementing the version number correctly. The latest version was {self.latest_version}, so the new version must be higher than this."
self.conversation_history[-1]["content"] += error_prompt
else:
return {'type': 'error', 'message': f"There was an error processing the AI's response after {MAX_RETRIES} attempts. Please try again."}

return {'type': 'error', 'message': f"Failed to get a valid response from the AI after {MAX_RETRIES} attempts. Please try again."}

return {
"type": "error",
"message": f"There was an error processing the AI's response after {MAX_RETRIES} attempts. Please try again.",
}

return {
"type": "error",
"message": f"Failed to get a valid response from the AI after {MAX_RETRIES} attempts. Please try again.",
}

except Exception as e:
print("Unexpected error in process_input")
return {'type': 'error', 'message': f"An unexpected error occurred: {str(e)}"}
return {
"type": "error",
"message": f"An unexpected error occurred: {str(e)}",
}

@staticmethod
def compare_versions(v1, v2):
v1_parts = list(map(int, v1.split('.')))
v2_parts = list(map(int, v2.split('.')))
v1_parts = list(map(int, v1.split(".")))
v2_parts = list(map(int, v2.split(".")))
return (v1_parts > v2_parts) - (v1_parts < v2_parts)

def run_generated_code(self, filename, requirements):
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
script_path = os.path.join(project_root, self.file_handler.output_dir, filename)
req_path = os.path.join(project_root, self.file_handler.output_dir, requirements)
req_path = os.path.join(
project_root, self.file_handler.output_dir, requirements
)

activation_command = self.env_manager.get_activation_command()

new_packages = self.env_manager.install_requirements(req_path)

script_content = f"""
Expand All @@ -93,7 +135,7 @@ def run_generated_code(self, filename, requirements):
script_content += 'echo "New dependencies installed:"\n'
for package in new_packages:
script_content += f'echo " - {package}"\n'

script_content += f"""
echo "Running {filename}..."
python "{script_path}"
Expand All @@ -104,4 +146,4 @@ def run_generated_code(self, filename, requirements):
self.terminal_manager.run_in_terminal(script_content)

def is_task_in_progress(self):
return bool(self.conversation_history)
return bool(self.conversation_history)
Loading

0 comments on commit ee2dde5

Please sign in to comment.