From e8a893156e097d8c964d0a8ff195b00fdb536fad Mon Sep 17 00:00:00 2001 From: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com> Date: Wed, 12 Apr 2023 13:45:54 -0400 Subject: [PATCH 01/24] Implemented .env file API key storage --- .env.sample | 1 + .gitignore | 2 ++ README.md | 5 ++++- wolverine.py | 8 ++++---- 4 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 .env.sample diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..3ad03db --- /dev/null +++ b/.env.sample @@ -0,0 +1 @@ +OPENAI_API_KEY=your_api_key \ No newline at end of file diff --git a/.gitignore b/.gitignore index 673fe09..32fabad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ venv openai_key.txt +.venv +.env \ No newline at end of file diff --git a/README.md b/README.md index 55813f7..c4f589f 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,11 @@ For a quick demonstration see my [demo video on twitter](https://twitter.com/bio python3 -m venv venv source venv/bin/activate pip install -r requirements.txt + cp .env.sample .env -Add your openAI api key to `openai_key.txt` - _warning!_ by default this uses GPT-4 and may make many repeated calls to the api. +Add your openAI api key to `.env` + +_warning!_ By default wolverine uses GPT-4 and may make many repeated calls to the api. ## Example Usage diff --git a/wolverine.py b/wolverine.py index 42f7ff8..f1d910d 100644 --- a/wolverine.py +++ b/wolverine.py @@ -5,13 +5,14 @@ import os import shutil import subprocess import sys - import openai from termcolor import cprint +from dotenv import load_dotenv + # Set up the OpenAI API -with open("openai_key.txt") as f: - openai.api_key = f.read().strip() +load_dotenv() +openai.api_key = os.getenv("OPENAI_API_KEY") def run_script(script_name, script_args): @@ -51,7 +52,6 @@ def send_error_to_gpt(file_path, args, error_message, model): ) # print(prompt) - response = openai.ChatCompletion.create( model=model, messages=[ From e65a4d080aedf2c0a4c09753cc559ff998c71fc4 Mon Sep 17 00:00:00 2001 From: Prayag Shah <34435248+prayagnshah@users.noreply.github.com> Date: Fri, 14 Apr 2023 00:10:36 -0300 Subject: [PATCH 02/24] adding flag for user confirmation - Modified the code to ask for changes to be applied. If they say yes then it will make the change or else code will stop running. --- wolverine.py | 49 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/wolverine.py b/wolverine.py index 42f7ff8..19fc95b 100644 --- a/wolverine.py +++ b/wolverine.py @@ -94,16 +94,9 @@ def apply_changes(file_path, changes_json): elif operation == "InsertAfter": file_lines.insert(line, content + "\n") - with open(file_path, "w") as f: - f.writelines(file_lines) + # Ask for user confirmation before writing changes + print("\nChanges to be made:") - # Print explanations - cprint("Explanations:", "blue") - for explanation in explanations: - cprint(f"- {explanation}", "blue") - - # Show the diff - print("\nChanges:") diff = difflib.unified_diff(original_file_lines, file_lines, lineterm="") for line in diff: if line.startswith("+"): @@ -113,6 +106,36 @@ def apply_changes(file_path, changes_json): else: print(line, end="") + confirmation = input("Do you want to apply these changes? (y/n): ") + if confirmation.lower() == "y": + with open(file_path, "w") as f: + f.writelines(file_lines) + + # Print explanations + cprint("Explanations:", "blue") + for explanation in explanations: + cprint(f"- {explanation}", "blue") + + # Show the diff + print("\nChanges:") + diff = difflib.unified_diff( + original_file_lines, file_lines, lineterm="") + for line in diff: + if line.startswith("+"): + cprint(line, "green", end="") + elif line.startswith("-"): + cprint(line, "red", end="") + else: + print(line, end="") + + print("Changes applied.") + # sys.exit(0) + + # Ending the code once they hit n or N + else: + print("Changes not applied") + sys.exit(0) + def main(script_name, *script_args, revert=False, model="gpt-4"): if revert: @@ -140,10 +163,10 @@ def main(script_name, *script_args, revert=False, model="gpt-4"): print("Output:", output) json_response = send_error_to_gpt( - file_path=script_name, - args=script_args, - error_message=output, - model=model, + file_path=script_name, + args=script_args, + error_message=output, + model=model, ) apply_changes(script_name, json_response) cprint("Changes applied. Rerunning...", "blue") From 4863df689877d0628520a10346c6ad7cbb7cd9cd Mon Sep 17 00:00:00 2001 From: Hemang Joshi Date: Fri, 14 Apr 2023 10:27:32 +0530 Subject: [PATCH 03/24] added `star-history` added `star-history` --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 55813f7..7df05b7 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,7 @@ This is just a quick prototype I threw together in a few hours. There are many p - multiple files / codebases: send GPT everything that appears in the stacktrace - graceful handling of large files - should we just send GPT relevant classes / functions? - extension to languages other than python + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=biobootloader/wolverine&type=Date)](https://star-history.com/#biobootloader/wolverine) From 6afb4db2ffc7878e2a125cd53917a1abfacb8790 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Fri, 14 Apr 2023 16:37:05 +0900 Subject: [PATCH 04/24] fix typo in README.md reliablity -> reliability --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 55813f7..0a8cae3 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This is just a quick prototype I threw together in a few hours. There are many p - add flags to customize usage, such as asking for user confirmation before running changed code - further iterations on the edit format that GPT responds in. Currently it struggles a bit with indentation, but I'm sure that can be improved -- a suite of example buggy files that we can test prompts on to ensure reliablity and measure improvement +- a suite of example buggy files that we can test prompts on to ensure reliability and measure improvement - multiple files / codebases: send GPT everything that appears in the stacktrace - graceful handling of large files - should we just send GPT relevant classes / functions? - extension to languages other than python From 3d14f31511970709ad25f0656d95f55195075fd4 Mon Sep 17 00:00:00 2001 From: Alessandro Annini Date: Fri, 14 Apr 2023 14:42:56 +0200 Subject: [PATCH 05/24] feat: :sparkles: can debug javascript files --- wolverine.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/wolverine.py b/wolverine.py index 42f7ff8..3b50d18 100644 --- a/wolverine.py +++ b/wolverine.py @@ -25,6 +25,17 @@ def run_script(script_name, script_args): return result.decode("utf-8"), 0 +def run_node(script_name, script_args): + script_args = [str(arg) for arg in script_args] + try: + result = subprocess.check_output( + ["node", script_name, *script_args], stderr=subprocess.STDOUT + ) + except subprocess.CalledProcessError as e: + return e.output.decode("utf-8"), e.returncode + return result.decode("utf-8"), 0 + + def send_error_to_gpt(file_path, args, error_message, model): with open(file_path, "r") as f: file_lines = f.readlines() @@ -38,8 +49,7 @@ def send_error_to_gpt(file_path, args, error_message, model): initial_prompt_text = f.read() prompt = ( - initial_prompt_text + - "\n\n" + initial_prompt_text + "\n\n" "Here is the script that needs fixing:\n\n" f"{file_with_lines}\n\n" "Here are the arguments it was provided:\n\n" @@ -114,7 +124,7 @@ def apply_changes(file_path, changes_json): print(line, end="") -def main(script_name, *script_args, revert=False, model="gpt-4"): +def main(script_name, *script_args, revert=False, model="gpt-3.5-turbo"): if revert: backup_file = script_name + ".bak" if os.path.exists(backup_file): @@ -129,7 +139,12 @@ def main(script_name, *script_args, revert=False, model="gpt-4"): shutil.copy(script_name, script_name + ".bak") while True: - output, returncode = run_script(script_name, script_args) + output = "" + returncode = 0 + if script_name.endswith(".js"): + output, returncode = run_node(script_name, script_args) + else: + output, returncode = run_script(script_name, script_args) if returncode == 0: cprint("Script ran successfully.", "blue") @@ -140,10 +155,10 @@ def main(script_name, *script_args, revert=False, model="gpt-4"): print("Output:", output) json_response = send_error_to_gpt( - file_path=script_name, - args=script_args, - error_message=output, - model=model, + file_path=script_name, + args=script_args, + error_message=output, + model=model, ) apply_changes(script_name, json_response) cprint("Changes applied. Rerunning...", "blue") From 49c6173c9b5216da0eff7d8fa4340e27b72be2d5 Mon Sep 17 00:00:00 2001 From: Alessandro Annini Date: Fri, 14 Apr 2023 14:43:32 +0200 Subject: [PATCH 06/24] chore: add buggy javascript file to test new feature --- buggy_script.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 buggy_script.js diff --git a/buggy_script.js b/buggy_script.js new file mode 100644 index 0000000..76ed038 --- /dev/null +++ b/buggy_script.js @@ -0,0 +1,25 @@ +const subtractNumbers = (a, b) => a - b; + +const multiplyNumbers = (a, b) => a * b; + +const divideNumbers = (a, b) => a / b; + +function calculate(operation, num1, num2) { + let result = ''; + if (operation == 'add') { + result = addNumbers(num1, num2); + } else if (operation == 'subtract') { + result = subtractNumbers(num1, num2); + } else if (operation == 'multiply') { + result = multiplyNumbers(num1, num2); + } else if (operation == 'divide') { + result = divideNumbers(num1, num2); + } else { + console.log('Invalid operation'); + } + + return res; +} + +const [, , operation, num1, num2] = process.argv; +calculate(operation, num1, num2); From 9af5480b89ec58edc11bf8b721eefc137e197d59 Mon Sep 17 00:00:00 2001 From: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com> Date: Fri, 14 Apr 2023 16:53:02 -0400 Subject: [PATCH 07/24] Added python-dotenv to requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 9d61d58..3923778 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,7 @@ multidict==6.0.4 openai==0.27.2 pycodestyle==2.10.0 pyflakes==3.0.1 +python-dotenv==1.0.0 requests==2.28.2 six==1.16.0 termcolor==2.2.0 From 6343f6f50be274a49f850426c382cede5652ad62 Mon Sep 17 00:00:00 2001 From: biobootloader <128252497+biobootloader@users.noreply.github.com> Date: Fri, 14 Apr 2023 13:59:31 -0700 Subject: [PATCH 08/24] Apply suggestions from code review --- .env.sample | 2 +- .gitignore | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.env.sample b/.env.sample index 3ad03db..9b73729 100644 --- a/.env.sample +++ b/.env.sample @@ -1 +1 @@ -OPENAI_API_KEY=your_api_key \ No newline at end of file +OPENAI_API_KEY=your_api_key diff --git a/.gitignore b/.gitignore index 32fabad..9c3fa66 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ venv -openai_key.txt .venv -.env \ No newline at end of file +.env From c62f91eaeed80501ca3bcc6d15d243bb8aa65a7a Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Thu, 13 Apr 2023 11:23:44 -0400 Subject: [PATCH 09/24] Update .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9c3fa66..f617754 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ venv -.venv +openai_key.txt .env +env/ +.vscode/ From 7c072fba2ab3bea728ca5dc3c7b16dc05e3dc54a Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Thu, 13 Apr 2023 11:24:41 -0400 Subject: [PATCH 10/24] update prompt to make it pay attention to indentation --- prompt.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/prompt.txt b/prompt.txt index 4376ab2..ec0582a 100644 --- a/prompt.txt +++ b/prompt.txt @@ -4,10 +4,13 @@ Because you are part of an automated system, the format you respond in is very s In addition to the changes, please also provide short explanations of the what went wrong. A single explanation is required, but if you think it's helpful, feel free to provide more explanations for groups of more complicated changes. Be careful to use proper indentation and spacing in your changes. An example response could be: +Be ABSOLUTELY SURE to include the CORRECT INDENTATION when making replacements. + +example response: [ {"explanation": "this is just an example, this would usually be a brief explanation of what went wrong"}, {"operation": "InsertAfter", "line": 10, "content": "x = 1\ny = 2\nz = x * y"}, {"operation": "Delete", "line": 15, "content": ""}, - {"operation": "Replace", "line": 18, "content": "x += 1"}, + {"operation": "Replace", "line": 18, "content": " x += 1"}, {"operation": "Delete", "line": 20, "content": ""} ] From 0656a83da73dd9446406edabdcd607fc5bccc263 Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Thu, 13 Apr 2023 11:29:06 -0400 Subject: [PATCH 11/24] recursive calls if not json parsable - makes recursive calls to API (with a comment about it not being parsable) if response was not parsable - pass prompt.txt as system prompt - use env var for `DEFAULT_MODEL` - use env var for OPENAI_API_KEY --- wolverine.py | 103 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 29 deletions(-) diff --git a/wolverine.py b/wolverine.py index f1d910d..d9eff4a 100644 --- a/wolverine.py +++ b/wolverine.py @@ -1,18 +1,27 @@ import difflib -import fire import json import os import shutil import subprocess import sys -import openai + +import fire +from dotenv import load_dotenv from termcolor import cprint from dotenv import load_dotenv -# Set up the OpenAI API load_dotenv() -openai.api_key = os.getenv("OPENAI_API_KEY") + +import openai + +openai.api_key = os.environ.get("OPENAI_API_KEY") + +DEFAULT_MODEL = os.environ.get("DEFAULT_MODEL", "gpt-4") + + +with open("prompt.txt") as f: + SYSTEM_PROMPT = f.read() def run_script(script_name, script_args): @@ -26,7 +35,47 @@ def run_script(script_name, script_args): return result.decode("utf-8"), 0 -def send_error_to_gpt(file_path, args, error_message, model): +def send_error_to_gpt(file_path, args, error_message, model=DEFAULT_MODEL): + def json_validated_response(model, messages): + """ + This function is needed because the API can return a non-json response. + This will run recursively until a valid json response is returned. + """ + response = openai.ChatCompletion.create( + model=model, + messages=messages, + temperature=0.5, + ) + messages.append(response.choices[0].message) + content = response.choices[0].message.content + # see if json can be parsed + try: + json_start_index = content.index( + "[" + ) # find the starting position of the JSON data + json_data = content[ + json_start_index: + ] # extract the JSON data from the response string + json_response = json.loads(json_data) + except (json.decoder.JSONDecodeError, ValueError) as e: + cprint(f"{e}. Re-running the query.", "red") + # debug + cprint(f"\n\GPT RESPONSE:\n\n{content}\n\n", "yellow") + # append a user message that says the json is invalid + messages.append( + { + "role": "user", + "content": "Your response could not be parsed by json.loads. Please restate your last message as pure JSON.", + } + ) + # rerun the api call + return json_validated_response(model, messages) + except Exception as e: + cprint(f"Unknown error: {e}", "red") + cprint(f"\n\GPT RESPONSE:\n\n{content}\n\n", "yellow") + raise e + return json_response + with open(file_path, "r") as f: file_lines = f.readlines() @@ -35,12 +84,7 @@ def send_error_to_gpt(file_path, args, error_message, model): file_with_lines.append(str(i + 1) + ": " + line) file_with_lines = "".join(file_with_lines) - with open("prompt.txt") as f: - initial_prompt_text = f.read() - prompt = ( - initial_prompt_text + - "\n\n" "Here is the script that needs fixing:\n\n" f"{file_with_lines}\n\n" "Here are the arguments it was provided:\n\n" @@ -52,26 +96,27 @@ def send_error_to_gpt(file_path, args, error_message, model): ) # print(prompt) - response = openai.ChatCompletion.create( - model=model, - messages=[ - { - "role": "user", - "content": prompt, - } - ], - temperature=1.0, - ) + messages = [ + { + "role": "system", + "content": SYSTEM_PROMPT, + }, + { + "role": "user", + "content": prompt, + }, + ] - return response.choices[0].message.content.strip() + return json_validated_response(model, messages) -def apply_changes(file_path, changes_json): +def apply_changes(file_path, changes: list): + """ + Pass changes as loaded json (list of dicts) + """ with open(file_path, "r") as f: original_file_lines = f.readlines() - changes = json.loads(changes_json) - # Filter out explanation elements operation_changes = [change for change in changes if "operation" in change] explanations = [ @@ -114,7 +159,7 @@ def apply_changes(file_path, changes_json): print(line, end="") -def main(script_name, *script_args, revert=False, model="gpt-4"): +def main(script_name, *script_args, revert=False, model=DEFAULT_MODEL): if revert: backup_file = script_name + ".bak" if os.path.exists(backup_file): @@ -140,11 +185,11 @@ def main(script_name, *script_args, revert=False, model="gpt-4"): print("Output:", output) json_response = send_error_to_gpt( - file_path=script_name, - args=script_args, - error_message=output, - model=model, + file_path=script_name, + args=script_args, + error_message=output, ) + apply_changes(script_name, json_response) cprint("Changes applied. Rerunning...", "blue") From 923f7057e36016208f4dbfdf227a0953eba59c47 Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Thu, 13 Apr 2023 11:35:24 -0400 Subject: [PATCH 12/24] update readme - updated readme to mention .env - added model arg back --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8e5e62e..401b812 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ For a quick demonstration see my [demo video on twitter](https://twitter.com/bio pip install -r requirements.txt cp .env.sample .env -Add your openAI api key to `.env` +Add your openAI api key to `.env` - _warning!_ by default this uses GPT-4 and may make many repeated calls to the api. -_warning!_ By default wolverine uses GPT-4 and may make many repeated calls to the api. + OPENAI_API_KEY=sk-abcdefghijklmopqrstuvwxyz ## Example Usage @@ -29,6 +29,10 @@ You can also run with other models, but be warned they may not adhere to the edi python wolverine.py --model=gpt-3.5-turbo buggy_script.py "subtract" 20 3 +If you want to use GPT-3.5 by default instead of GPT-4 add this to `.env`: + + DEFAULT_MODEL=gpt-3.5-turbo + ## Future Plans This is just a quick prototype I threw together in a few hours. There are many possible extensions and contributions are welcome: From 2497fb816b862ac1b5d27751c5742fb8171d4207 Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Fri, 14 Apr 2023 16:29:45 -0400 Subject: [PATCH 13/24] move json_validated_response to standalone function --- wolverine.py | 91 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/wolverine.py b/wolverine.py index d9eff4a..903bf0c 100644 --- a/wolverine.py +++ b/wolverine.py @@ -35,47 +35,49 @@ def run_script(script_name, script_args): return result.decode("utf-8"), 0 -def send_error_to_gpt(file_path, args, error_message, model=DEFAULT_MODEL): - def json_validated_response(model, messages): - """ - This function is needed because the API can return a non-json response. - This will run recursively until a valid json response is returned. - """ - response = openai.ChatCompletion.create( - model=model, - messages=messages, - temperature=0.5, +def json_validated_response(model, messages): + """ + This function is needed because the API can return a non-json response. + This will run recursively until a valid json response is returned. + todo: might want to stop after a certain number of retries + """ + response = openai.ChatCompletion.create( + model=model, + messages=messages, + temperature=0.5, + ) + messages.append(response.choices[0].message) + content = response.choices[0].message.content + # see if json can be parsed + try: + json_start_index = content.index( + "[" + ) # find the starting position of the JSON data + json_data = content[ + json_start_index: + ] # extract the JSON data from the response string + json_response = json.loads(json_data) + except (json.decoder.JSONDecodeError, ValueError) as e: + cprint(f"{e}. Re-running the query.", "red") + # debug + cprint(f"\n\GPT RESPONSE:\n\n{content}\n\n", "yellow") + # append a user message that says the json is invalid + messages.append( + { + "role": "user", + "content": "Your response could not be parsed by json.loads. Please restate your last message as pure JSON.", + } ) - messages.append(response.choices[0].message) - content = response.choices[0].message.content - # see if json can be parsed - try: - json_start_index = content.index( - "[" - ) # find the starting position of the JSON data - json_data = content[ - json_start_index: - ] # extract the JSON data from the response string - json_response = json.loads(json_data) - except (json.decoder.JSONDecodeError, ValueError) as e: - cprint(f"{e}. Re-running the query.", "red") - # debug - cprint(f"\n\GPT RESPONSE:\n\n{content}\n\n", "yellow") - # append a user message that says the json is invalid - messages.append( - { - "role": "user", - "content": "Your response could not be parsed by json.loads. Please restate your last message as pure JSON.", - } - ) - # rerun the api call - return json_validated_response(model, messages) - except Exception as e: - cprint(f"Unknown error: {e}", "red") - cprint(f"\n\GPT RESPONSE:\n\n{content}\n\n", "yellow") - raise e - return json_response + # rerun the api call + return json_validated_response(model, messages) + except Exception as e: + cprint(f"Unknown error: {e}", "red") + cprint(f"\nGPT RESPONSE:\n\n{content}\n\n", "yellow") + raise e + return json_response + +def send_error_to_gpt(file_path, args, error_message, model=DEFAULT_MODEL): with open(file_path, "r") as f: file_lines = f.readlines() @@ -106,6 +108,16 @@ def send_error_to_gpt(file_path, args, error_message, model=DEFAULT_MODEL): "content": prompt, }, ] + messages = [ + { + "role": "system", + "content": SYSTEM_PROMPT, + }, + { + "role": "user", + "content": prompt, + }, + ] return json_validated_response(model, messages) @@ -188,6 +200,7 @@ def main(script_name, *script_args, revert=False, model=DEFAULT_MODEL): file_path=script_name, args=script_args, error_message=output, + model=model, ) apply_changes(script_name, json_response) From dd174cf30eafca66a06e08654854c93ec5297fe0 Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Fri, 14 Apr 2023 17:15:07 -0400 Subject: [PATCH 14/24] add DEFAULT_MODEL to .env.sample + fix typo --- .env.sample | 1 + wolverine.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.env.sample b/.env.sample index 9b73729..f2177b3 100644 --- a/.env.sample +++ b/.env.sample @@ -1 +1,2 @@ OPENAI_API_KEY=your_api_key +DEFAULT_MODEL=gpt-3.5-turbo diff --git a/wolverine.py b/wolverine.py index 903bf0c..3b6fb4e 100644 --- a/wolverine.py +++ b/wolverine.py @@ -60,7 +60,7 @@ def json_validated_response(model, messages): except (json.decoder.JSONDecodeError, ValueError) as e: cprint(f"{e}. Re-running the query.", "red") # debug - cprint(f"\n\GPT RESPONSE:\n\n{content}\n\n", "yellow") + cprint(f"\nGPT RESPONSE:\n\n{content}\n\n", "yellow") # append a user message that says the json is invalid messages.append( { From b044882dc391d878c570d56ae5e64bb1045d0ec0 Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Fri, 14 Apr 2023 17:37:27 -0400 Subject: [PATCH 15/24] remove duplicate code from rebase --- wolverine.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/wolverine.py b/wolverine.py index 3b6fb4e..0501f1b 100644 --- a/wolverine.py +++ b/wolverine.py @@ -108,16 +108,6 @@ def send_error_to_gpt(file_path, args, error_message, model=DEFAULT_MODEL): "content": prompt, }, ] - messages = [ - { - "role": "system", - "content": SYSTEM_PROMPT, - }, - { - "role": "user", - "content": prompt, - }, - ] return json_validated_response(model, messages) From e1d0a790f8941a74c4857ac8404c4c1c9e4fb6ed Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Fri, 14 Apr 2023 17:46:18 -0400 Subject: [PATCH 16/24] cleanup --- .env.sample | 2 +- README.md | 6 +++--- wolverine.py | 9 +++------ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.env.sample b/.env.sample index f2177b3..2184c45 100644 --- a/.env.sample +++ b/.env.sample @@ -1,2 +1,2 @@ OPENAI_API_KEY=your_api_key -DEFAULT_MODEL=gpt-3.5-turbo +#DEFAULT_MODEL=gpt-3.5-turbo diff --git a/README.md b/README.md index 401b812..f671b4e 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ For a quick demonstration see my [demo video on twitter](https://twitter.com/bio pip install -r requirements.txt cp .env.sample .env -Add your openAI api key to `.env` - _warning!_ by default this uses GPT-4 and may make many repeated calls to the api. +Add your openAI api key to `.env` - OPENAI_API_KEY=sk-abcdefghijklmopqrstuvwxyz +_warning!_ by default this uses GPT-4 and may make many repeated calls to the api. ## Example Usage @@ -29,7 +29,7 @@ You can also run with other models, but be warned they may not adhere to the edi python wolverine.py --model=gpt-3.5-turbo buggy_script.py "subtract" 20 3 -If you want to use GPT-3.5 by default instead of GPT-4 add this to `.env`: +If you want to use GPT-3.5 by default instead of GPT-4 uncomment the default model line in `.env`: DEFAULT_MODEL=gpt-3.5-turbo diff --git a/wolverine.py b/wolverine.py index 0501f1b..535db10 100644 --- a/wolverine.py +++ b/wolverine.py @@ -1,21 +1,18 @@ import difflib +import fire import json import os import shutil import subprocess import sys +import openai -import fire -from dotenv import load_dotenv from termcolor import cprint from dotenv import load_dotenv load_dotenv() - -import openai - -openai.api_key = os.environ.get("OPENAI_API_KEY") +openai.api_key = os.getenv("OPENAI_API_KEY") DEFAULT_MODEL = os.environ.get("DEFAULT_MODEL", "gpt-4") From 4db9d1bf43438a7809e47bd1bd140cad8b3b12e1 Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Fri, 14 Apr 2023 17:49:09 -0400 Subject: [PATCH 17/24] more cleanup --- .gitignore | 2 +- wolverine.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f617754..da34ea7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ venv -openai_key.txt +.venv .env env/ .vscode/ diff --git a/wolverine.py b/wolverine.py index 535db10..194a0fc 100644 --- a/wolverine.py +++ b/wolverine.py @@ -6,11 +6,11 @@ import shutil import subprocess import sys import openai - from termcolor import cprint from dotenv import load_dotenv +# Set up the OpenAI API load_dotenv() openai.api_key = os.getenv("OPENAI_API_KEY") From fe87faa2fb709b782217093ecf88379e153a0f58 Mon Sep 17 00:00:00 2001 From: Felix Boehme Date: Fri, 14 Apr 2023 17:49:48 -0400 Subject: [PATCH 18/24] cleanup --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f671b4e..e3608e6 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ For a quick demonstration see my [demo video on twitter](https://twitter.com/bio Add your openAI api key to `.env` -_warning!_ by default this uses GPT-4 and may make many repeated calls to the api. +_warning!_ By default wolverine uses GPT-4 and may make many repeated calls to the api. ## Example Usage From e1c413fae2b38a2d8898c3c0ec03d5193bde91f4 Mon Sep 17 00:00:00 2001 From: Prayag Shah <34435248+prayagnshah@users.noreply.github.com> Date: Sat, 15 Apr 2023 02:10:25 -0300 Subject: [PATCH 19/24] updated the flag --confirm as required - Updated the flag --confirm=True which will allow user to say yes or no before making changes to the file. - If flag is not used then it will right away make changes to the file. - Updated the readme with an example. --- README.md | 4 ++++ wolverine.py | 57 ++++++++++++++++++++++++++-------------------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 55813f7..c988276 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@ You can also run with other models, but be warned they may not adhere to the edi python wolverine.py --model=gpt-3.5-turbo buggy_script.py "subtract" 20 3 +You can also use flag `--confirm=True` which will ask you `yes or no` before making changes to the file. If flag is not used then it will apply the changes to the file + + python wolverine.py buggy_script.py "subtract" 20 3 --confirm=True + ## Future Plans This is just a quick prototype I threw together in a few hours. There are many possible extensions and contributions are welcome: diff --git a/wolverine.py b/wolverine.py index 19fc95b..42001b6 100644 --- a/wolverine.py +++ b/wolverine.py @@ -66,7 +66,8 @@ def send_error_to_gpt(file_path, args, error_message, model): return response.choices[0].message.content.strip() -def apply_changes(file_path, changes_json): +# Added the flag confirm. Once user use flag confirm then it will ask for confirmation before applying the changes. +def apply_changes(file_path, changes_json, confirm=False): with open(file_path, "r") as f: original_file_lines = f.readlines() @@ -106,38 +107,38 @@ def apply_changes(file_path, changes_json): else: print(line, end="") - confirmation = input("Do you want to apply these changes? (y/n): ") - if confirmation.lower() == "y": - with open(file_path, "w") as f: - f.writelines(file_lines) + # Checking if user used confirm flag + if confirm: + confirmation = input("Do you want to apply these changes? (y/n): ") + if confirmation.lower() != "y": + print("Changes not applied") + sys.exit(0) - # Print explanations - cprint("Explanations:", "blue") - for explanation in explanations: - cprint(f"- {explanation}", "blue") + with open(file_path, "w") as f: + f.writelines(file_lines) - # Show the diff - print("\nChanges:") - diff = difflib.unified_diff( - original_file_lines, file_lines, lineterm="") - for line in diff: - if line.startswith("+"): - cprint(line, "green", end="") - elif line.startswith("-"): - cprint(line, "red", end="") - else: - print(line, end="") + # Print explanations + cprint("Explanations:", "blue") + for explanation in explanations: + cprint(f"- {explanation}", "blue") - print("Changes applied.") - # sys.exit(0) + # Show the diff + print("\nChanges:") + diff = difflib.unified_diff( + original_file_lines, file_lines, lineterm="") + for line in diff: + if line.startswith("+"): + cprint(line, "green", end="") + elif line.startswith("-"): + cprint(line, "red", end="") + else: + print(line, end="") - # Ending the code once they hit n or N - else: - print("Changes not applied") - sys.exit(0) + print("Changes applied.") -def main(script_name, *script_args, revert=False, model="gpt-4"): +# Added the flag confirm. Once user use flag confirm then it will ask for confirmation before applying the changes. +def main(script_name, *script_args, revert=False, model="gpt-4", confirm=False): if revert: backup_file = script_name + ".bak" if os.path.exists(backup_file): @@ -168,7 +169,7 @@ def main(script_name, *script_args, revert=False, model="gpt-4"): error_message=output, model=model, ) - apply_changes(script_name, json_response) + apply_changes(script_name, json_response, confirm=confirm) cprint("Changes applied. Rerunning...", "blue") From 946e15ff2099f662dd7287e720c67f231faa4153 Mon Sep 17 00:00:00 2001 From: Prayag Shah <34435248+prayagnshah@users.noreply.github.com> Date: Sat, 15 Apr 2023 02:22:57 -0300 Subject: [PATCH 20/24] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 742aaaf9d1ddfee29cc49c993c5d8d0480e53f0a Merge: f2d21e7 fe87faa Author: biobootloader <128252497+biobootloader@users.noreply.github.com> Date: Fri Apr 14 15:44:12 2023 -0700 Merge pull request #13 from fsboehme/main more robust parsing of JSON (+ indentation) commit fe87faa2fb709b782217093ecf88379e153a0f58 Author: Felix Boehme Date: Fri Apr 14 17:49:48 2023 -0400 cleanup commit 4db9d1bf43438a7809e47bd1bd140cad8b3b12e1 Author: Felix Boehme Date: Fri Apr 14 17:49:09 2023 -0400 more cleanup commit e1d0a790f8941a74c4857ac8404c4c1c9e4fb6ed Author: Felix Boehme Date: Fri Apr 14 17:46:18 2023 -0400 cleanup commit b044882dc391d878c570d56ae5e64bb1045d0ec0 Author: Felix Boehme Date: Fri Apr 14 17:37:27 2023 -0400 remove duplicate code from rebase commit dd174cf30eafca66a06e08654854c93ec5297fe0 Author: Felix Boehme Date: Fri Apr 14 17:15:07 2023 -0400 add DEFAULT_MODEL to .env.sample + fix typo commit 2497fb816b862ac1b5d27751c5742fb8171d4207 Author: Felix Boehme Date: Fri Apr 14 16:29:45 2023 -0400 move json_validated_response to standalone function commit 923f7057e36016208f4dbfdf227a0953eba59c47 Author: Felix Boehme Date: Thu Apr 13 11:35:24 2023 -0400 update readme - updated readme to mention .env - added model arg back commit 0656a83da73dd9446406edabdcd607fc5bccc263 Author: Felix Boehme Date: Thu Apr 13 11:29:06 2023 -0400 recursive calls if not json parsable - makes recursive calls to API (with a comment about it not being parsable) if response was not parsable - pass prompt.txt as system prompt - use env var for `DEFAULT_MODEL` - use env var for OPENAI_API_KEY commit 7c072fba2ab3bea728ca5dc3c7b16dc05e3dc54a Author: Felix Boehme Date: Thu Apr 13 11:24:41 2023 -0400 update prompt to make it pay attention to indentation commit c62f91eaeed80501ca3bcc6d15d243bb8aa65a7a Author: Felix Boehme Date: Thu Apr 13 11:23:44 2023 -0400 Update .gitignore commit f2d21e7b93517261161b78acd9fbaf580f6158c1 Merge: 0420860 6343f6f Author: biobootloader <128252497+biobootloader@users.noreply.github.com> Date: Fri Apr 14 13:59:44 2023 -0700 Merge pull request #12 from chriscarrollsmith/main Implemented .env file API key storage commit 6343f6f50be274a49f850426c382cede5652ad62 Author: biobootloader <128252497+biobootloader@users.noreply.github.com> Date: Fri Apr 14 13:59:31 2023 -0700 Apply suggestions from code review commit d87ebfa46f6b830bcfc5c543b149942ce68453cd Merge: 9af5480 75f08e2 Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com> Date: Fri Apr 14 16:53:25 2023 -0400 Merge branch 'main' of https://github.com/chriscarrollsmith/wolverine commit 9af5480b89ec58edc11bf8b721eefc137e197d59 Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com> Date: Fri Apr 14 16:53:02 2023 -0400 Added python-dotenv to requirements.txt commit 75f08e285293b4482e4fec74a2055629863bc90f Merge: e8a8931 0420860 Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com> Date: Fri Apr 14 16:50:29 2023 -0400 Merge pull request #1 from biobootloader/main Reconcile with master branch commit 04208605fe403b70ac5945b4fbcd86e481b8e73d Merge: d547822 6afb4db Author: biobootloader <128252497+biobootloader@users.noreply.github.com> Date: Fri Apr 14 13:22:53 2023 -0700 Merge pull request #20 from eltociear/patch-1 fix typo in README.md commit d54782230c9b30109108e511604c61f8c0c0a001 Merge: 1b9649e 4863df6 Author: biobootloader <128252497+biobootloader@users.noreply.github.com> Date: Fri Apr 14 13:19:43 2023 -0700 Merge pull request #17 from hemangjoshi37a/main added `star-history` ⭐⭐⭐⭐⭐ commit 6afb4db2ffc7878e2a125cd53917a1abfacb8790 Author: Ikko Eltociear Ashimine Date: Fri Apr 14 16:37:05 2023 +0900 fix typo in README.md reliablity -> reliability commit 4863df689877d0628520a10346c6ad7cbb7cd9cd Author: Hemang Joshi Date: Fri Apr 14 10:27:32 2023 +0530 added `star-history` added `star-history` commit e8a893156e097d8c964d0a8ff195b00fdb536fad Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com> Date: Wed Apr 12 13:45:54 2023 -0400 Implemented .env file API key storage --- .env.sample | 2 + .gitignore | 5 ++- README.md | 15 +++++++- prompt.txt | 5 ++- requirements.txt | 1 + wolverine.py | 97 ++++++++++++++++++++++++++++++++++-------------- 6 files changed, 94 insertions(+), 31 deletions(-) create mode 100644 .env.sample diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..2184c45 --- /dev/null +++ b/.env.sample @@ -0,0 +1,2 @@ +OPENAI_API_KEY=your_api_key +#DEFAULT_MODEL=gpt-3.5-turbo diff --git a/.gitignore b/.gitignore index 673fe09..da34ea7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ venv -openai_key.txt +.venv +.env +env/ +.vscode/ diff --git a/README.md b/README.md index c988276..98571ca 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,11 @@ For a quick demonstration see my [demo video on twitter](https://twitter.com/bio python3 -m venv venv source venv/bin/activate pip install -r requirements.txt + cp .env.sample .env -Add your openAI api key to `openai_key.txt` - _warning!_ by default this uses GPT-4 and may make many repeated calls to the api. +Add your openAI api key to `.env` + +_warning!_ By default wolverine uses GPT-4 and may make many repeated calls to the api. ## Example Usage @@ -30,13 +33,21 @@ You can also use flag `--confirm=True` which will ask you `yes or no` before mak python wolverine.py buggy_script.py "subtract" 20 3 --confirm=True +If you want to use GPT-3.5 by default instead of GPT-4 uncomment the default model line in `.env`: + + DEFAULT_MODEL=gpt-3.5-turbo + ## Future Plans This is just a quick prototype I threw together in a few hours. There are many possible extensions and contributions are welcome: - add flags to customize usage, such as asking for user confirmation before running changed code - further iterations on the edit format that GPT responds in. Currently it struggles a bit with indentation, but I'm sure that can be improved -- a suite of example buggy files that we can test prompts on to ensure reliablity and measure improvement +- a suite of example buggy files that we can test prompts on to ensure reliability and measure improvement - multiple files / codebases: send GPT everything that appears in the stacktrace - graceful handling of large files - should we just send GPT relevant classes / functions? - extension to languages other than python + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=biobootloader/wolverine&type=Date)](https://star-history.com/#biobootloader/wolverine) diff --git a/prompt.txt b/prompt.txt index 4376ab2..ec0582a 100644 --- a/prompt.txt +++ b/prompt.txt @@ -4,10 +4,13 @@ Because you are part of an automated system, the format you respond in is very s In addition to the changes, please also provide short explanations of the what went wrong. A single explanation is required, but if you think it's helpful, feel free to provide more explanations for groups of more complicated changes. Be careful to use proper indentation and spacing in your changes. An example response could be: +Be ABSOLUTELY SURE to include the CORRECT INDENTATION when making replacements. + +example response: [ {"explanation": "this is just an example, this would usually be a brief explanation of what went wrong"}, {"operation": "InsertAfter", "line": 10, "content": "x = 1\ny = 2\nz = x * y"}, {"operation": "Delete", "line": 15, "content": ""}, - {"operation": "Replace", "line": 18, "content": "x += 1"}, + {"operation": "Replace", "line": 18, "content": " x += 1"}, {"operation": "Delete", "line": 20, "content": ""} ] diff --git a/requirements.txt b/requirements.txt index 9d61d58..3923778 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,7 @@ multidict==6.0.4 openai==0.27.2 pycodestyle==2.10.0 pyflakes==3.0.1 +python-dotenv==1.0.0 requests==2.28.2 six==1.16.0 termcolor==2.2.0 diff --git a/wolverine.py b/wolverine.py index 42001b6..363e3da 100644 --- a/wolverine.py +++ b/wolverine.py @@ -5,13 +5,20 @@ import os import shutil import subprocess import sys - import openai from termcolor import cprint +from dotenv import load_dotenv + # Set up the OpenAI API -with open("openai_key.txt") as f: - openai.api_key = f.read().strip() +load_dotenv() +openai.api_key = os.getenv("OPENAI_API_KEY") + +DEFAULT_MODEL = os.environ.get("DEFAULT_MODEL", "gpt-4") + + +with open("prompt.txt") as f: + SYSTEM_PROMPT = f.read() def run_script(script_name, script_args): @@ -25,7 +32,49 @@ def run_script(script_name, script_args): return result.decode("utf-8"), 0 -def send_error_to_gpt(file_path, args, error_message, model): +def json_validated_response(model, messages): + """ + This function is needed because the API can return a non-json response. + This will run recursively until a valid json response is returned. + todo: might want to stop after a certain number of retries + """ + response = openai.ChatCompletion.create( + model=model, + messages=messages, + temperature=0.5, + ) + messages.append(response.choices[0].message) + content = response.choices[0].message.content + # see if json can be parsed + try: + json_start_index = content.index( + "[" + ) # find the starting position of the JSON data + json_data = content[ + json_start_index: + ] # extract the JSON data from the response string + json_response = json.loads(json_data) + except (json.decoder.JSONDecodeError, ValueError) as e: + cprint(f"{e}. Re-running the query.", "red") + # debug + cprint(f"\nGPT RESPONSE:\n\n{content}\n\n", "yellow") + # append a user message that says the json is invalid + messages.append( + { + "role": "user", + "content": "Your response could not be parsed by json.loads. Please restate your last message as pure JSON.", + } + ) + # rerun the api call + return json_validated_response(model, messages) + except Exception as e: + cprint(f"Unknown error: {e}", "red") + cprint(f"\nGPT RESPONSE:\n\n{content}\n\n", "yellow") + raise e + return json_response + + +def send_error_to_gpt(file_path, args, error_message, model=DEFAULT_MODEL): with open(file_path, "r") as f: file_lines = f.readlines() @@ -34,12 +83,7 @@ def send_error_to_gpt(file_path, args, error_message, model): file_with_lines.append(str(i + 1) + ": " + line) file_with_lines = "".join(file_with_lines) - with open("prompt.txt") as f: - initial_prompt_text = f.read() - prompt = ( - initial_prompt_text + - "\n\n" "Here is the script that needs fixing:\n\n" f"{file_with_lines}\n\n" "Here are the arguments it was provided:\n\n" @@ -51,28 +95,27 @@ def send_error_to_gpt(file_path, args, error_message, model): ) # print(prompt) + messages = [ + { + "role": "system", + "content": SYSTEM_PROMPT, + }, + { + "role": "user", + "content": prompt, + }, + ] - response = openai.ChatCompletion.create( - model=model, - messages=[ - { - "role": "user", - "content": prompt, - } - ], - temperature=1.0, - ) - - return response.choices[0].message.content.strip() + return json_validated_response(model, messages) -# Added the flag confirm. Once user use flag confirm then it will ask for confirmation before applying the changes. -def apply_changes(file_path, changes_json, confirm=False): +def apply_changes(file_path, changes: list, confirm=False): + """ + Pass changes as loaded json (list of dicts) + """ with open(file_path, "r") as f: original_file_lines = f.readlines() - changes = json.loads(changes_json) - # Filter out explanation elements operation_changes = [change for change in changes if "operation" in change] explanations = [ @@ -137,8 +180,7 @@ def apply_changes(file_path, changes_json, confirm=False): print("Changes applied.") -# Added the flag confirm. Once user use flag confirm then it will ask for confirmation before applying the changes. -def main(script_name, *script_args, revert=False, model="gpt-4", confirm=False): +def main(script_name, *script_args, revert=False, model=DEFAULT_MODEL, confirm=False): if revert: backup_file = script_name + ".bak" if os.path.exists(backup_file): @@ -169,6 +211,7 @@ def main(script_name, *script_args, revert=False, model="gpt-4", confirm=False): error_message=output, model=model, ) + apply_changes(script_name, json_response, confirm=confirm) cprint("Changes applied. Rerunning...", "blue") From fdbaaa3e84658e2755aef3dd0b9246920a5b446d Mon Sep 17 00:00:00 2001 From: Prayag Shah <34435248+prayagnshah@users.noreply.github.com> Date: Sat, 15 Apr 2023 02:28:13 -0300 Subject: [PATCH 21/24] updated the flag --confirm as required - Updated the flag --confirm=True which will allow user to say yes or no before making changes to the file. - If flag is not used then it will right away make changes to the file. - Updated the readme with an example. --- README.md | 8 ++++---- wolverine.py | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 98571ca..6d29bd7 100644 --- a/README.md +++ b/README.md @@ -29,14 +29,14 @@ You can also run with other models, but be warned they may not adhere to the edi python wolverine.py --model=gpt-3.5-turbo buggy_script.py "subtract" 20 3 -You can also use flag `--confirm=True` which will ask you `yes or no` before making changes to the file. If flag is not used then it will apply the changes to the file - - python wolverine.py buggy_script.py "subtract" 20 3 --confirm=True - If you want to use GPT-3.5 by default instead of GPT-4 uncomment the default model line in `.env`: DEFAULT_MODEL=gpt-3.5-turbo +You can also use flag `--confirm=True` which will ask you `yes or no` before making changes to the file. If flag is not used then it will apply the changes to the file + + python wolverine.py buggy_script.py "subtract" 20 3 --confirm=True + ## Future Plans This is just a quick prototype I threw together in a few hours. There are many possible extensions and contributions are welcome: diff --git a/wolverine.py b/wolverine.py index 363e3da..dbd77a0 100644 --- a/wolverine.py +++ b/wolverine.py @@ -108,6 +108,8 @@ def send_error_to_gpt(file_path, args, error_message, model=DEFAULT_MODEL): return json_validated_response(model, messages) +# Added the flag -confirm which will ask user before writing changes to file + def apply_changes(file_path, changes: list, confirm=False): """ From 8abc8893bb0caf1eab6711d8a52665c0721c3e52 Mon Sep 17 00:00:00 2001 From: Alessandro Annini Date: Sat, 15 Apr 2023 10:10:34 +0200 Subject: [PATCH 22/24] refactor: better implementation fr py/js files execution --- wolverine.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/wolverine.py b/wolverine.py index e9d12d6..2e96b08 100644 --- a/wolverine.py +++ b/wolverine.py @@ -23,10 +23,18 @@ with open("prompt.txt") as f: def run_script(script_name, script_args): script_args = [str(arg) for arg in script_args] + """ + If script_name.endswith(".py") then run with python + else run with node + """ + subprocess_args = ( + [sys.executable, script_name, *script_args] + if script_name.endswith(".py") + else ["node", script_name, *script_args] + ) + try: - result = subprocess.check_output( - [sys.executable, script_name, *script_args], stderr=subprocess.STDOUT - ) + result = subprocess.check_output(subprocess_args, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: return e.output.decode("utf-8"), e.returncode return result.decode("utf-8"), 0 @@ -173,12 +181,7 @@ def main(script_name, *script_args, revert=False, model=DEFAULT_MODEL): shutil.copy(script_name, script_name + ".bak") while True: - output = "" - returncode = 0 - if script_name.endswith(".js"): - output, returncode = run_node(script_name, script_args) - else: - output, returncode = run_script(script_name, script_args) + output, returncode = run_script(script_name, script_args) if returncode == 0: cprint("Script ran successfully.", "blue") From 0f538fecae4b129e0e9f19066f7f8d0548404ff2 Mon Sep 17 00:00:00 2001 From: Alessandro Annini Date: Sat, 15 Apr 2023 10:10:59 +0200 Subject: [PATCH 23/24] chore: update buggy js script file --- buggy_script.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/buggy_script.js b/buggy_script.js index 76ed038..ad05a00 100644 --- a/buggy_script.js +++ b/buggy_script.js @@ -1,8 +1,14 @@ -const subtractNumbers = (a, b) => a - b; +const subtractNumbers = (a, b) => { + return a - b; +}; -const multiplyNumbers = (a, b) => a * b; +const multiplyNumbers = (a, b) => { + return a * b; +}; -const divideNumbers = (a, b) => a / b; +const divideNumbers = (a, b) => { + return a / b; +}; function calculate(operation, num1, num2) { let result = ''; From c20b79ea281f8c8da8dbcf2161f7ccf33e48d0c4 Mon Sep 17 00:00:00 2001 From: biobootloader <128252497+biobootloader@users.noreply.github.com> Date: Sat, 15 Apr 2023 11:20:12 -0700 Subject: [PATCH 24/24] Update wolverine.py --- wolverine.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/wolverine.py b/wolverine.py index ca6b18c..363e3da 100644 --- a/wolverine.py +++ b/wolverine.py @@ -109,8 +109,6 @@ def send_error_to_gpt(file_path, args, error_message, model=DEFAULT_MODEL): return json_validated_response(model, messages) -# Added the flag -confirm which will ask user before writing changes to file - def apply_changes(file_path, changes: list, confirm=False): """ Pass changes as loaded json (list of dicts)