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

Sweep: Add repo config file #246

Closed
lukejagg opened this issue Jul 5, 2023 · 7 comments · Fixed by #252 · 4 remaining pull requests
Closed

Sweep: Add repo config file #246

lukejagg opened this issue Jul 5, 2023 · 7 comments · Fixed by #252 · 4 remaining pull requests
Labels
sweep Assigns Sweep to an issue or pull request.

Comments

@lukejagg
Copy link
Contributor

lukejagg commented Jul 5, 2023

Description

Create new file for sweepai/utils/repo_config.py, that will go from a "repo" type, read the "sweep.yaml" file, and load the settings into the RepoConfig class.

Example:
class RepoConfig
def init(self, repo: Repository):
...

be sure to import the correct packages at top of file

Relevant files

No response

@lukejagg lukejagg added the sweep Assigns Sweep to an issue or pull request. label Jul 5, 2023
@sweep-ai
Copy link
Contributor

sweep-ai bot commented Jul 5, 2023

Hey @lukejagg,

I've started working on this PR. Here's a rough summary of my plan:

  1. I'll create a new file sweepai/utils/repo_config.py that will contain a RepoConfig class. This class will handle the loading of settings from the sweep.yaml file.
  2. The RepoConfig class will have a method to read the sweep.yaml file and load the settings.
  3. I'll modify the sweepai/utils/__init__.py file to import the new RepoConfig class so it can be used elsewhere in the codebase.

Give me a minute!

Some code snippets I looked at (click to expand). If some file is missing from here, you can mention the path in the ticket description.

import shutil
import modal
import os
import time
import re
import github
from github import Github
from github.Repository import Repository
from loguru import logger
from jwt import encode
import requests
from tqdm import tqdm
from sweepai.core.entities import Snippet
from sweepai.utils.config import SweepConfig
from sweepai.utils.constants import APP_ID, DB_NAME
from sweepai.utils.event_logger import posthog
def make_valid_string(string: str):
pattern = r"[^\w./-]+"
return re.sub(pattern, "_", string)
def get_jwt():
signing_key = os.environ["GITHUB_APP_PEM"]
app_id = APP_ID
payload = {"iat": int(time.time()), "exp": int(time.time()) + 600, "iss": app_id}
return encode(payload, signing_key, algorithm="RS256")
def get_token(installation_id: int):
jwt = get_jwt()
headers = {
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
}
response = requests.post(
f"https://api.github.com/app/installations/{int(installation_id)}/access_tokens",
headers=headers,
)
return response.json()["token"]
def get_github_client(installation_id: int):
token = get_token(installation_id)
return Github(token)
def get_installation_id(username: str):
jwt = get_jwt()
response = requests.get(
f"https://api.github.com/users/{username}/installation",
headers={
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
},
)
obj = response.json()
try:
return obj["id"]
except:
raise Exception("Could not get installation id, probably not installed")
def display_directory_tree(
root_path,
includes: list[str] = [],
excludes: list[str] = [".git"],
):
def display_directory_tree_helper(
current_dir,
indent="",
) -> str:
files = os.listdir(current_dir)
files.sort()
tree = ""
for item_name in files:
full_path = os.path.join(current_dir, item_name)[len(root_path) + 1 :]
if item_name in excludes:
continue
file_path = os.path.join(current_dir, item_name)
if os.path.isdir(file_path):
if full_path in includes:
tree += f"{indent}|- {item_name}/\n"
tree += display_directory_tree_helper(
file_path, indent + "| "
)
else:
tree += f"{indent}|- {item_name}/...\n"
else:
tree += f"{indent}|- {item_name}\n"
return tree
tree = display_directory_tree_helper(root_path)
lines = tree.splitlines()
return "\n".join([line[3:] for line in lines])
def get_file_list(root_directory: str) -> str:

sweep/README.md

Lines 1 to 104 in c23ac48

<p align="center">
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/sweep-banner-github.png">
</p>
<p align="center">
<i>Spend time reviewing code generated by AI, not writing it.</i>
</p>
<p align="center">
<a href="https://sweep.dev/">🌐 Website</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://docs.sweep.dev/">📚 Docs</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://discord.gg/sweep-ai">📢 Discord</a>
</p>
<b>Sweep</b> allows you to create and review GitHub issues with ease.
Simply describe any issue and Sweep will do the rest.
It will plan out what needs to be done, what changes to make, and write the changes to a PR.
Supported languages: Python, Javascript/Typescript, Rust, Go, Java/C#, C++ and anything else GPT-4 supports
---
## ✨ Demo
For the best experience, [install Sweep](https://github.com/apps/sweep-ai) to one of your repos and see the magic happen.
[Demo](https://github.com/sweepai/sweep/assets/44910023/365ec29f-7317-40a7-9b5e-0af02f2b0e47)
## 🚀 Getting Started
### 🖥️ Sweep Chat
Sweep Chat allows you to interact with Sweep locally and will sync with GitHub. You can plan out your changes with Sweep, and then Sweep can create a pull request for you.
1. Install [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Run `pip install sweepai && sweep`. Note that you need python 3.10 or greater.
3. This should spin up a GitHub auth flow in your browser. Copy-paste the 🔵 blue 8-digit code from your terminal into the page. Then wait a few seconds and it should spin up Sweep Chat. You should only need to do the auth once.
4. Pick a repo from the dropdown at the top (the Github app must be installed on this repo). Then start chatting with Sweep Chat. Relevant searched files will show up on the right. Sweep Chat can make PRs if you ask it to create a PR.
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/gradio-screenshot.png">
💡 You can force dark mode by going to http://127.0.0.1:7861/?__theme=dark.
#### From Source
If you want the nightly build and or if the latest build has issues.
1. `git clone https://github.com/sweepai/sweep && poetry install`
2. `python sweepai/app/cli.py`. Note that you need python 3.10 or greater.
### ✨ Sweep Github App
Setting up Sweep is as simple as adding the GitHub bot to a repo, then creating an issue for the bot to address.
1. Add the [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Create new issue in repo, like "Sweep: Write tests"
3. "👀" means it is taking a look, and it will generate the desired code
4. "🚀" means the bot has finished its job and created a PR
## 🤝 Contributing
Contributions are welcome and greatly appreciated! For detailed guidelines on how to contribute, please see the [CONTRIBUTING.md](CONTRIBUTING.md) file. In essence, you'll need to fork the repository, create a new branch for your feature or bug fix, commit your changes, and open a pull request.
For more detailed docs, see [🚀 Quickstart](https://docs.sweep.dev/start).
---
## 📘 Story
We were frustrated by small tickets, like simple bug fixes, annoying refactors, and small features, each task requiring us to open our IDE to fix simple bugs. So, we decided to leverage the capabilities of ChatGPT to address this directly in GitHub.
Unlike existing AI solutions, this can solve entire tickets and can be parallelized: developers can spin up 10 tickets and Sweep will address them all at once.
## 📚 The Stack
- GPT-4 32k 0613 (default) / Claude v1.3 100k
- ActiveLoop DeepLake for Vector DB with MiniLM L12 as our embeddings model
- Modal Labs for infra + deployment
## 🌠 Features
* Automatic feature development
* PR auto self-review + comment handling (effectively [Reflexion](https://arxiv.org/abs/2303.11366))
* Address developer comments after PR is created
* Code snippets embedding-based search
* Chain-of-Thought retrieval using GPT Functions
## 🗺️ Roadmap
We're currently working on responding to linters and external search. For more, see [🗺️ Roadmap](https://docs.sweep.dev/roadmap).
---
<h2 align="center">
Contributors
</h2>
<p align="center">
Thank you for your contribution!
</p>
<p align="center">
<a href="https://github.com/sweepai/sweep/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sweepai/sweep" />
</a>
</p>
<p align="center">
and, of course, Sweep!
</p>

"""
This file should be split into environment and config files
"""
PREFIX = "prod"
DB_NAME = PREFIX + "-db"
API_NAME = PREFIX + "-api"
UTILS_NAME = PREFIX + "-utils"
SLACK_NAME = PREFIX + "-slack"
BOT_TOKEN_NAME = PREFIX + "-bot-token"
if PREFIX == "prod":
BOT_TOKEN_NAME = "bot-token"
SWEEP_LOGIN = "sweep-ai[bot]"
if PREFIX == "prod":
APP_ID = 307814
ENV = PREFIX
elif PREFIX == "dev2":
APP_ID = 327588
ENV = PREFIX
SWEEP_LOGIN = "sweep-canary[bot]"
elif PREFIX == "dev":
APP_ID = 324098
ENV = PREFIX
SWEEP_LOGIN = "sweep-nightly[bot]"
LABEL_NAME = "sweep"
LABEL_COLOR = "#9400D3"

from typing import Any
import webbrowser
import httpx
from pydantic import BaseModel
import requests
import json
from loguru import logger
from sweepai.app.config import SweepChatConfig
from sweepai.core.entities import Function, PullRequest, Snippet
from sweepai.utils.constants import PREFIX
create_pr_function = Function(
name="create_pr",
description="Creates a PR.",
parameters={
"properties": {
"plan": {
"type": "array",
"items": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "The file path to change."
},
"instructions": {
"type": "string",
"description": "Concise NATURAL LANGUAGE summary of what to change in each file. There should be absolutely NO code, only English.",
"example": [
"Refactor the algorithm by moving the main function to the top of the file.",
"Change the implementation to recursion"
]
},
},
"required": ["file_path", "instructions"]
},
"description": "A list of files to modify or create and corresponding instructions."
},
"title": {
"type": "string",
"description": "Title of PR",
},
"summary": {
"type": "string",
"description": "Detailed summary of PR",
},
"branch": {
"type": "string",
"description": "Name of branch to create PR in.",
},
},
"required": ["plan", "title", "summary", "branch"]
}
)
create_pr_function_call = {"name": "create_pr"}
def break_json(raw_json: str):
# turns something like {"function_call": {"arguments": " \""}}{"function_call": {"arguments": "summary"}} into two objects
try:
yield json.loads(raw_json)

sweep/tests/test_diffs.py

Lines 506 to 738 in c23ac48

# # Initialize the model
# init_model()
# # Train the model
# train_model()
# if __name__ == "__main__":
# main()
# ```
# """
# print(format_contents(test_file))
# test_file = """```python
# import torch
# import torchvision
# import torchvision.transforms as transforms
# def load_data():
# # Load the training and testing data
# # This is just a placeholder and should be replaced with your actual data loading code
# pass
# def init_model():
# # Initialize the model
# # This is just a placeholder and should be replaced with your actual model initialization code
# pass
# reg = ```abc```
# def train_model():
# # Train the model
# # This is just a placeholder and should be replaced with your actual model training code
# pass
# def main():
# # Load the data
# load_data()
# # Initialize the model
# init_model()
# # Train the model
# train_model()
# if __name__ == "__main__":
# main()
# ```
# """
# print(format_contents(test_file))
test_file = """
test.py
```python
import json
from github import Github
import gradio as gr
from loguru import logger
import webbrowser
from gradio import Button
from sweepai.app.api_client import APIClient, create_pr_function, create_pr_function_call
from sweepai.app.config import SweepChatConfig
from sweepai.core.entities import Snippet
config = SweepChatConfig.load()
api_client = APIClient(config=config)
pr_summary_template = '''💡 I'll create the following PR:
**{title}**
{summary}
Here is my plan:
{plan}
Reply with "ok" to create the PR or anything else to propose changes.'''
github_client = Github(config.github_pat)
repos = list(github_client.get_user().get_repos())
css = '''
footer {
visibility: hidden;
}
pre, code {
white-space: pre-wrap !important;
word-break: break-all !important;
}
#snippets {
height: 750px;
overflow-y: scroll;
}
'''
def get_files_recursively(repo, path=''):
path_to_contents = {}
try:
contents = repo.get_contents(path)
files = []
while contents:
file_content = contents.pop(0)
if file_content.type == 'dir':
contents.extend(repo.get_contents(file_content.path))
else:
try:
decoded_contents = file_content.decoded_content.decode("utf-8")
except:
continue
if decoded_contents:
path_to_contents[file_content.path] = file_content.decoded_content.decode("utf-8")
files.append(file_content.path)
return sorted(files), path_to_contents
except Exception as e:
logger.error(e)
return [], path_to_contents
def create_pr_button_click():
global proposed_pr
if proposed_pr:
chat_history = [[None, f"⏳ Creating PR..."]]
pull_request = api_client.create_pr(
file_change_requests=[(item["file_path"], item["instructions"]) for item in proposed_pr["plan"]],
pull_request={
"title": proposed_pr["title"],
"content": proposed_pr["summary"],
"branch_name": proposed_pr["branch"],
},
messages=chat_history,
)
chat_history[-1][1] = f"✅ PR created at {pull_request['html_url']}"
return chat_history
with gr.Blocks(theme=gr.themes.Soft(), title="Sweep Chat", css=css) as demo:
with gr.Row():
with gr.Column():
repo_full_name = gr.Dropdown(choices=[repo.full_name for repo in repos], label="Repo full name", value=config.repo_full_name or "")
with gr.Column(scale=2):
repo = github_client.get_repo(config.repo_full_name)
all_files, path_to_contents = get_files_recursively(repo)
file_names = gr.Dropdown(choices=all_files, multiselect=True, label="Files")
with gr.Row():
with gr.Column(scale=2):
chatbot = gr.Chatbot(height=750)
with gr.Column():
snippets_text = gr.Markdown(value="### Relevant snippets", elem_id="snippets")
create_pr_button = Button("Create PR", create_pr_button_click)
msg = gr.Textbox(label="Message to Sweep", placeholder="Write unit tests for OpenAI calls")
# clear = gr.ClearButton([msg, chatbot, snippets_text])
proposed_pr: str | None = None
searched = False
selected_snippets = []
file_to_str = {}
def repo_name_change(repo_full_name):
global installation_id
try:
config.repo_full_name = repo_full_name
api_client.config = config
installation_id = api_client.get_installation_id()
assert installation_id
config.installation_id = installation_id
api_client.config = config
config.save()
return ""
except Exception as e:
webbrowser.open_new_tab("https://github.com/apps/sweep-ai")
config.repo_full_name = None
config.installation_id = None
config.save()
api_client.config = config
raise e
repo_full_name.change(repo_name_change, [repo_full_name], [msg])
def build_string():
global selected_snippets
global file_to_str
for snippet in selected_snippets:
file_name = snippet.file_path
if file_name not in file_to_str:
add_file_to_dict(file_name)
snippets_text = "### Relevant snippets:\n" + "\n\n".join([file_to_str[snippet.file_path] for snippet in selected_snippets])
return snippets_text
def add_file_to_dict(file_name):
global file_to_str
global path_to_contents
if file_name in path_to_contents:
file_contents = path_to_contents[file_name]
else:
file_contents = repo.get_contents(file_name).decoded_content.decode('utf-8')
file_contents_split = file_contents.split("\n")
length = len(file_contents_split)
backtick, escaped_backtick = "`", "\\`"
preview = "\n".join(file_contents_split[:3]).replace(backtick, escaped_backtick)
file_to_str[file_name] = f'{file_name}:0:{length}\n```python\n{preview}\n...\n```'
def file_names_change(file_names):
global selected_snippets
global file_to_str
global path_to_contents
selected_snippets = [Snippet(content=path_to_contents[file_name], start=0, end=path_to_contents[file_name].count('\n'), file_path=file_name) for file_name in file_names]
return file_names, build_string()
file_names.change(file_names_change, [file_names], [file_names, snippets_text])
def handle_message_submit(repo_full_name: str, user_message: str, history: list[tuple[str | None, str | None]]):
if not repo_full_name:
raise Exception("Set the repository name first")
return gr.update(value="", interactive=False), history + [[user_message, None]]
def handle_message_stream(chat_history: list[tuple[str | None, str | None]], snippets_text, file_names):
global selected_snippets
global searched
message = chat_history[-1][0]
yield chat_history, snippets_text, file_names
if not selected_snippets:
searched = True
# Searching for relevant snippets
chat_history[-1][1] = "Searching for relevant snippets..."
snippets_text = build_string()
yield chat_history, snippets_text, file_names
logger.info("Fetching relevant snippets...")
selected_snippets += api_client.search(chat_history[-1][0], 3)
snippets_text = build_string()
file_names = [snippet.file_path for snippet in selected_snippets]
yield chat_history, snippets_text, file_names
logger.info("Fetched relevant snippets.")
chat_history[-1][1] = "Found relevant snippets."
# Update using chat_history
snippets_text = build_string()


I'm a bot that handles simple bugs and feature requests but I might make mistakes. Please be kind!

@sweep-nightly
Copy link
Contributor

sweep-nightly bot commented Jul 5, 2023

Hey @lukejagg! 👋

I've started working on your PR to add the repo config file. Here's a rough summary of my plan:


💡 I'll create the following PR:

Add repo config file

Create a new file sweepai/utils/repo_config.py that will read the sweep.yaml file and load the settings into the RepoConfig class.

Here is my plan:

  • Create the repo_config.py file in the sweepai/utils directory.
  • Implement the logic to read the sweep.yaml file and load the settings into the RepoConfig class.

Reply with "ok" to create the PR or anything else to propose changes.


Give me a minute! 😊

Some code snippets I looked at (click to expand). If some file is missing from here, you can mention the path in the ticket description.

import shutil
import modal
import os
import time
import re
import github
from github import Github
from github.Repository import Repository
from loguru import logger
from jwt import encode
import requests
from tqdm import tqdm
from sweepai.core.entities import Snippet
from sweepai.utils.config import SweepConfig
from sweepai.utils.constants import APP_ID, DB_NAME
from sweepai.utils.event_logger import posthog
def make_valid_string(string: str):
pattern = r"[^\w./-]+"
return re.sub(pattern, "_", string)
def get_jwt():
signing_key = os.environ["GITHUB_APP_PEM"]
app_id = APP_ID
payload = {"iat": int(time.time()), "exp": int(time.time()) + 600, "iss": app_id}
return encode(payload, signing_key, algorithm="RS256")
def get_token(installation_id: int):
jwt = get_jwt()
headers = {
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
}
response = requests.post(
f"https://api.github.com/app/installations/{int(installation_id)}/access_tokens",
headers=headers,
)
return response.json()["token"]
def get_github_client(installation_id: int):
token = get_token(installation_id)
return Github(token)
def get_installation_id(username: str):
jwt = get_jwt()
response = requests.get(
f"https://api.github.com/users/{username}/installation",
headers={
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
},
)
obj = response.json()
try:
return obj["id"]
except:
raise Exception("Could not get installation id, probably not installed")
def display_directory_tree(
root_path,
includes: list[str] = [],
excludes: list[str] = [".git"],
):
def display_directory_tree_helper(
current_dir,
indent="",
) -> str:
files = os.listdir(current_dir)
files.sort()
tree = ""
for item_name in files:
full_path = os.path.join(current_dir, item_name)[len(root_path) + 1 :]
if item_name in excludes:
continue
file_path = os.path.join(current_dir, item_name)
if os.path.isdir(file_path):
if full_path in includes:
tree += f"{indent}|- {item_name}/\n"
tree += display_directory_tree_helper(
file_path, indent + "| "
)
else:
tree += f"{indent}|- {item_name}/...\n"
else:
tree += f"{indent}|- {item_name}\n"
return tree
tree = display_directory_tree_helper(root_path)
lines = tree.splitlines()
return "\n".join([line[3:] for line in lines])
def get_file_list(root_directory: str) -> str:

sweep/README.md

Lines 1 to 104 in c23ac48

<p align="center">
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/sweep-banner-github.png">
</p>
<p align="center">
<i>Spend time reviewing code generated by AI, not writing it.</i>
</p>
<p align="center">
<a href="https://sweep.dev/">🌐 Website</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://docs.sweep.dev/">📚 Docs</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://discord.gg/sweep-ai">📢 Discord</a>
</p>
<b>Sweep</b> allows you to create and review GitHub issues with ease.
Simply describe any issue and Sweep will do the rest.
It will plan out what needs to be done, what changes to make, and write the changes to a PR.
Supported languages: Python, Javascript/Typescript, Rust, Go, Java/C#, C++ and anything else GPT-4 supports
---
## ✨ Demo
For the best experience, [install Sweep](https://github.com/apps/sweep-ai) to one of your repos and see the magic happen.
[Demo](https://github.com/sweepai/sweep/assets/44910023/365ec29f-7317-40a7-9b5e-0af02f2b0e47)
## 🚀 Getting Started
### 🖥️ Sweep Chat
Sweep Chat allows you to interact with Sweep locally and will sync with GitHub. You can plan out your changes with Sweep, and then Sweep can create a pull request for you.
1. Install [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Run `pip install sweepai && sweep`. Note that you need python 3.10 or greater.
3. This should spin up a GitHub auth flow in your browser. Copy-paste the 🔵 blue 8-digit code from your terminal into the page. Then wait a few seconds and it should spin up Sweep Chat. You should only need to do the auth once.
4. Pick a repo from the dropdown at the top (the Github app must be installed on this repo). Then start chatting with Sweep Chat. Relevant searched files will show up on the right. Sweep Chat can make PRs if you ask it to create a PR.
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/gradio-screenshot.png">
💡 You can force dark mode by going to http://127.0.0.1:7861/?__theme=dark.
#### From Source
If you want the nightly build and or if the latest build has issues.
1. `git clone https://github.com/sweepai/sweep && poetry install`
2. `python sweepai/app/cli.py`. Note that you need python 3.10 or greater.
### ✨ Sweep Github App
Setting up Sweep is as simple as adding the GitHub bot to a repo, then creating an issue for the bot to address.
1. Add the [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Create new issue in repo, like "Sweep: Write tests"
3. "👀" means it is taking a look, and it will generate the desired code
4. "🚀" means the bot has finished its job and created a PR
## 🤝 Contributing
Contributions are welcome and greatly appreciated! For detailed guidelines on how to contribute, please see the [CONTRIBUTING.md](CONTRIBUTING.md) file. In essence, you'll need to fork the repository, create a new branch for your feature or bug fix, commit your changes, and open a pull request.
For more detailed docs, see [🚀 Quickstart](https://docs.sweep.dev/start).
---
## 📘 Story
We were frustrated by small tickets, like simple bug fixes, annoying refactors, and small features, each task requiring us to open our IDE to fix simple bugs. So, we decided to leverage the capabilities of ChatGPT to address this directly in GitHub.
Unlike existing AI solutions, this can solve entire tickets and can be parallelized: developers can spin up 10 tickets and Sweep will address them all at once.
## 📚 The Stack
- GPT-4 32k 0613 (default) / Claude v1.3 100k
- ActiveLoop DeepLake for Vector DB with MiniLM L12 as our embeddings model
- Modal Labs for infra + deployment
## 🌠 Features
* Automatic feature development
* PR auto self-review + comment handling (effectively [Reflexion](https://arxiv.org/abs/2303.11366))
* Address developer comments after PR is created
* Code snippets embedding-based search
* Chain-of-Thought retrieval using GPT Functions
## 🗺️ Roadmap
We're currently working on responding to linters and external search. For more, see [🗺️ Roadmap](https://docs.sweep.dev/roadmap).
---
<h2 align="center">
Contributors
</h2>
<p align="center">
Thank you for your contribution!
</p>
<p align="center">
<a href="https://github.com/sweepai/sweep/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sweepai/sweep" />
</a>
</p>
<p align="center">
and, of course, Sweep!
</p>

"""
This file should be split into environment and config files
"""
PREFIX = "prod"
DB_NAME = PREFIX + "-db"
API_NAME = PREFIX + "-api"
UTILS_NAME = PREFIX + "-utils"
SLACK_NAME = PREFIX + "-slack"
BOT_TOKEN_NAME = PREFIX + "-bot-token"
if PREFIX == "prod":
BOT_TOKEN_NAME = "bot-token"
SWEEP_LOGIN = "sweep-ai[bot]"
if PREFIX == "prod":
APP_ID = 307814
ENV = PREFIX
elif PREFIX == "dev2":
APP_ID = 327588
ENV = PREFIX
SWEEP_LOGIN = "sweep-canary[bot]"
elif PREFIX == "dev":
APP_ID = 324098
ENV = PREFIX
SWEEP_LOGIN = "sweep-nightly[bot]"
LABEL_NAME = "sweep"
LABEL_COLOR = "#9400D3"

from typing import Any
import webbrowser
import httpx
from pydantic import BaseModel
import requests
import json
from loguru import logger
from sweepai.app.config import SweepChatConfig
from sweepai.core.entities import Function, PullRequest, Snippet
from sweepai.utils.constants import PREFIX
create_pr_function = Function(
name="create_pr",
description="Creates a PR.",
parameters={
"properties": {
"plan": {
"type": "array",
"items": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "The file path to change."
},
"instructions": {
"type": "string",
"description": "Concise NATURAL LANGUAGE summary of what to change in each file. There should be absolutely NO code, only English.",
"example": [
"Refactor the algorithm by moving the main function to the top of the file.",
"Change the implementation to recursion"
]
},
},
"required": ["file_path", "instructions"]
},
"description": "A list of files to modify or create and corresponding instructions."
},
"title": {
"type": "string",
"description": "Title of PR",
},
"summary": {
"type": "string",
"description": "Detailed summary of PR",
},
"branch": {
"type": "string",
"description": "Name of branch to create PR in.",
},
},
"required": ["plan", "title", "summary", "branch"]
}
)
create_pr_function_call = {"name": "create_pr"}
def break_json(raw_json: str):
# turns something like {"function_call": {"arguments": " \""}}{"function_call": {"arguments": "summary"}} into two objects
try:
yield json.loads(raw_json)

sweep/tests/test_diffs.py

Lines 506 to 738 in c23ac48

# # Initialize the model
# init_model()
# # Train the model
# train_model()
# if __name__ == "__main__":
# main()
# ```
# """
# print(format_contents(test_file))
# test_file = """```python
# import torch
# import torchvision
# import torchvision.transforms as transforms
# def load_data():
# # Load the training and testing data
# # This is just a placeholder and should be replaced with your actual data loading code
# pass
# def init_model():
# # Initialize the model
# # This is just a placeholder and should be replaced with your actual model initialization code
# pass
# reg = ```abc```
# def train_model():
# # Train the model
# # This is just a placeholder and should be replaced with your actual model training code
# pass
# def main():
# # Load the data
# load_data()
# # Initialize the model
# init_model()
# # Train the model
# train_model()
# if __name__ == "__main__":
# main()
# ```
# """
# print(format_contents(test_file))
test_file = """
test.py
```python
import json
from github import Github
import gradio as gr
from loguru import logger
import webbrowser
from gradio import Button
from sweepai.app.api_client import APIClient, create_pr_function, create_pr_function_call
from sweepai.app.config import SweepChatConfig
from sweepai.core.entities import Snippet
config = SweepChatConfig.load()
api_client = APIClient(config=config)
pr_summary_template = '''💡 I'll create the following PR:
**{title}**
{summary}
Here is my plan:
{plan}
Reply with "ok" to create the PR or anything else to propose changes.'''
github_client = Github(config.github_pat)
repos = list(github_client.get_user().get_repos())
css = '''
footer {
visibility: hidden;
}
pre, code {
white-space: pre-wrap !important;
word-break: break-all !important;
}
#snippets {
height: 750px;
overflow-y: scroll;
}
'''
def get_files_recursively(repo, path=''):
path_to_contents = {}
try:
contents = repo.get_contents(path)
files = []
while contents:
file_content = contents.pop(0)
if file_content.type == 'dir':
contents.extend(repo.get_contents(file_content.path))
else:
try:
decoded_contents = file_content.decoded_content.decode("utf-8")
except:
continue
if decoded_contents:
path_to_contents[file_content.path] = file_content.decoded_content.decode("utf-8")
files.append(file_content.path)
return sorted(files), path_to_contents
except Exception as e:
logger.error(e)
return [], path_to_contents
def create_pr_button_click():
global proposed_pr
if proposed_pr:
chat_history = [[None, f"⏳ Creating PR..."]]
pull_request = api_client.create_pr(
file_change_requests=[(item["file_path"], item["instructions"]) for item in proposed_pr["plan"]],
pull_request={
"title": proposed_pr["title"],
"content": proposed_pr["summary"],
"branch_name": proposed_pr["branch"],
},
messages=chat_history,
)
chat_history[-1][1] = f"✅ PR created at {pull_request['html_url']}"
return chat_history
with gr.Blocks(theme=gr.themes.Soft(), title="Sweep Chat", css=css) as demo:
with gr.Row():
with gr.Column():
repo_full_name = gr.Dropdown(choices=[repo.full_name for repo in repos], label="Repo full name", value=config.repo_full_name or "")
with gr.Column(scale=2):
repo = github_client.get_repo(config.repo_full_name)
all_files, path_to_contents = get_files_recursively(repo)
file_names = gr.Dropdown(choices=all_files, multiselect=True, label="Files")
with gr.Row():
with gr.Column(scale=2):
chatbot = gr.Chatbot(height=750)
with gr.Column():
snippets_text = gr.Markdown(value="### Relevant snippets", elem_id="snippets")
create_pr_button = Button("Create PR", create_pr_button_click)
msg = gr.Textbox(label="Message to Sweep", placeholder="Write unit tests for OpenAI calls")
# clear = gr.ClearButton([msg, chatbot, snippets_text])
proposed_pr: str | None = None
searched = False
selected_snippets = []
file_to_str = {}
def repo_name_change(repo_full_name):
global installation_id
try:
config.repo_full_name = repo_full_name
api_client.config = config
installation_id = api_client.get_installation_id()
assert installation_id
config.installation_id = installation_id
api_client.config = config
config.save()
return ""
except Exception as e:
webbrowser.open_new_tab("https://github.com/apps/sweep-ai")
config.repo_full_name = None
config.installation_id = None
config.save()
api_client.config = config
raise e
repo_full_name.change(repo_name_change, [repo_full_name], [msg])
def build_string():
global selected_snippets
global file_to_str
for snippet in selected_snippets:
file_name = snippet.file_path
if file_name not in file_to_str:
add_file_to_dict(file_name)
snippets_text = "### Relevant snippets:\n" + "\n\n".join([file_to_str[snippet.file_path] for snippet in selected_snippets])
return snippets_text
def add_file_to_dict(file_name):
global file_to_str
global path_to_contents
if file_name in path_to_contents:
file_contents = path_to_contents[file_name]
else:
file_contents = repo.get_contents(file_name).decoded_content.decode('utf-8')
file_contents_split = file_contents.split("\n")
length = len(file_contents_split)
backtick, escaped_backtick = "`", "\\`"
preview = "\n".join(file_contents_split[:3]).replace(backtick, escaped_backtick)
file_to_str[file_name] = f'{file_name}:0:{length}\n```python\n{preview}\n...\n```'
def file_names_change(file_names):
global selected_snippets
global file_to_str
global path_to_contents
selected_snippets = [Snippet(content=path_to_contents[file_name], start=0, end=path_to_contents[file_name].count('\n'), file_path=file_name) for file_name in file_names]
return file_names, build_string()
file_names.change(file_names_change, [file_names], [file_names, snippets_text])
def handle_message_submit(repo_full_name: str, user_message: str, history: list[tuple[str | None, str | None]]):
if not repo_full_name:
raise Exception("Set the repository name first")
return gr.update(value="", interactive=False), history + [[user_message, None]]
def handle_message_stream(chat_history: list[tuple[str | None, str | None]], snippets_text, file_names):
global selected_snippets
global searched
message = chat_history[-1][0]
yield chat_history, snippets_text, file_names
if not selected_snippets:
searched = True
# Searching for relevant snippets
chat_history[-1][1] = "Searching for relevant snippets..."
snippets_text = build_string()
yield chat_history, snippets_text, file_names
logger.info("Fetching relevant snippets...")
selected_snippets += api_client.search(chat_history[-1][0], 3)
snippets_text = build_string()
file_names = [snippet.file_path for snippet in selected_snippets]
yield chat_history, snippets_text, file_names
logger.info("Fetched relevant snippets.")
chat_history[-1][1] = "Found relevant snippets."
# Update using chat_history
snippets_text = build_string()


I'm a bot that handles simple bugs and feature requests but I might make mistakes. Please be kind!

@lukejagg
Copy link
Contributor Author

lukejagg commented Jul 5, 2023

This is for a GitHub bot, so the repo is not local. We have to use the github repo type instead, which should be somewhere else in the code. So, take the github repo as input into the class instead.

@sweep-ai
Copy link
Contributor

sweep-ai bot commented Jul 5, 2023

Hey @lukejagg,

I've started working on this PR. Here's a rough summary of my plan:

  1. I'll create a new file sweepai/utils/repo_config.py that will contain a RepoConfig class. This class will handle the loading of settings from the sweep.yaml file.
  2. The RepoConfig class will have a method to read the sweep.yaml file and load the settings.
  3. I'll modify the RepoConfig class to take a GitHub repo as input, as per your instructions.

Give me a minute!

Some code snippets I looked at (click to expand). If some file is missing from here, you can mention the path in the ticket description.

sweep/README.md

Lines 1 to 104 in c23ac48

<p align="center">
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/sweep-banner-github.png">
</p>
<p align="center">
<i>Spend time reviewing code generated by AI, not writing it.</i>
</p>
<p align="center">
<a href="https://sweep.dev/">🌐 Website</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://docs.sweep.dev/">📚 Docs</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://discord.gg/sweep-ai">📢 Discord</a>
</p>
<b>Sweep</b> allows you to create and review GitHub issues with ease.
Simply describe any issue and Sweep will do the rest.
It will plan out what needs to be done, what changes to make, and write the changes to a PR.
Supported languages: Python, Javascript/Typescript, Rust, Go, Java/C#, C++ and anything else GPT-4 supports
---
## ✨ Demo
For the best experience, [install Sweep](https://github.com/apps/sweep-ai) to one of your repos and see the magic happen.
[Demo](https://github.com/sweepai/sweep/assets/44910023/365ec29f-7317-40a7-9b5e-0af02f2b0e47)
## 🚀 Getting Started
### 🖥️ Sweep Chat
Sweep Chat allows you to interact with Sweep locally and will sync with GitHub. You can plan out your changes with Sweep, and then Sweep can create a pull request for you.
1. Install [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Run `pip install sweepai && sweep`. Note that you need python 3.10 or greater.
3. This should spin up a GitHub auth flow in your browser. Copy-paste the 🔵 blue 8-digit code from your terminal into the page. Then wait a few seconds and it should spin up Sweep Chat. You should only need to do the auth once.
4. Pick a repo from the dropdown at the top (the Github app must be installed on this repo). Then start chatting with Sweep Chat. Relevant searched files will show up on the right. Sweep Chat can make PRs if you ask it to create a PR.
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/gradio-screenshot.png">
💡 You can force dark mode by going to http://127.0.0.1:7861/?__theme=dark.
#### From Source
If you want the nightly build and or if the latest build has issues.
1. `git clone https://github.com/sweepai/sweep && poetry install`
2. `python sweepai/app/cli.py`. Note that you need python 3.10 or greater.
### ✨ Sweep Github App
Setting up Sweep is as simple as adding the GitHub bot to a repo, then creating an issue for the bot to address.
1. Add the [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Create new issue in repo, like "Sweep: Write tests"
3. "👀" means it is taking a look, and it will generate the desired code
4. "🚀" means the bot has finished its job and created a PR
## 🤝 Contributing
Contributions are welcome and greatly appreciated! For detailed guidelines on how to contribute, please see the [CONTRIBUTING.md](CONTRIBUTING.md) file. In essence, you'll need to fork the repository, create a new branch for your feature or bug fix, commit your changes, and open a pull request.
For more detailed docs, see [🚀 Quickstart](https://docs.sweep.dev/start).
---
## 📘 Story
We were frustrated by small tickets, like simple bug fixes, annoying refactors, and small features, each task requiring us to open our IDE to fix simple bugs. So, we decided to leverage the capabilities of ChatGPT to address this directly in GitHub.
Unlike existing AI solutions, this can solve entire tickets and can be parallelized: developers can spin up 10 tickets and Sweep will address them all at once.
## 📚 The Stack
- GPT-4 32k 0613 (default) / Claude v1.3 100k
- ActiveLoop DeepLake for Vector DB with MiniLM L12 as our embeddings model
- Modal Labs for infra + deployment
## 🌠 Features
* Automatic feature development
* PR auto self-review + comment handling (effectively [Reflexion](https://arxiv.org/abs/2303.11366))
* Address developer comments after PR is created
* Code snippets embedding-based search
* Chain-of-Thought retrieval using GPT Functions
## 🗺️ Roadmap
We're currently working on responding to linters and external search. For more, see [🗺️ Roadmap](https://docs.sweep.dev/roadmap).
---
<h2 align="center">
Contributors
</h2>
<p align="center">
Thank you for your contribution!
</p>
<p align="center">
<a href="https://github.com/sweepai/sweep/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sweepai/sweep" />
</a>
</p>
<p align="center">
and, of course, Sweep!
</p>

sweep/CONTRIBUTING.md

Lines 1 to 34 in c23ac48

# Contributing to Sweep AI
First off, thank you for considering contributing to Sweep AI. It's people like you that make Sweep AI such a great tool.
## Creating Issues
Before you submit an issue, please do a search in [open issues](https://github.com/sweepai/sweep/issues) to see if the issue or feature request has already been filed.
Use the provided issue template when creating a new issue. Fill in the template with as much detail as possible. The more detail you provide, the more likely that someone can help you.
Alternatively, you can use Sweep to create a ticket for the problem first. Simply describe the issue or feature request, and Sweep will create a ticket for it. This can help you understand the problem better and guide you in manually solving it.
You can also use Sweep to create tickets. Simply describe the issue or feature request, and Sweep will create a ticket for it.
Use the provided issue template when creating a new issue. Fill in the template with as much detail as possible. The more detail you provide, the more likely that someone can help you.
## Submitting Pull Requests
If you're working on an existing issue, respond to the issue and express interest in working on it. This helps other people know that the issue is active, and hopefully prevents duplicated efforts.
To submit a pull request, follow the following steps:
1. Fork the repository.
2. Create a new branch from `main`.
3. Make your changes.
4. Push your branch and submit a pull request to the `main` branch.
5. Await review. Respond to any comments or requests made by reviewers.
## Coding Standards
Please ensure your code adheres to the coding standards used throughout the project. This includes proper indentation, accurate comments, and clear, concise code.
## Community
Please be respectful and considerate of others. We're all here to learn and grow, so constructive, respectful communication is encouraged.

import shutil
import modal
import os
import time
import re
import github
from github import Github
from github.Repository import Repository
from loguru import logger
from jwt import encode
import requests
from tqdm import tqdm
from sweepai.core.entities import Snippet
from sweepai.utils.config import SweepConfig
from sweepai.utils.constants import APP_ID, DB_NAME
from sweepai.utils.event_logger import posthog
def make_valid_string(string: str):
pattern = r"[^\w./-]+"
return re.sub(pattern, "_", string)
def get_jwt():
signing_key = os.environ["GITHUB_APP_PEM"]
app_id = APP_ID
payload = {"iat": int(time.time()), "exp": int(time.time()) + 600, "iss": app_id}
return encode(payload, signing_key, algorithm="RS256")
def get_token(installation_id: int):
jwt = get_jwt()
headers = {
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
}
response = requests.post(
f"https://api.github.com/app/installations/{int(installation_id)}/access_tokens",
headers=headers,
)
return response.json()["token"]
def get_github_client(installation_id: int):
token = get_token(installation_id)
return Github(token)
def get_installation_id(username: str):
jwt = get_jwt()
response = requests.get(
f"https://api.github.com/users/{username}/installation",
headers={
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
},
)
obj = response.json()
try:
return obj["id"]
except:
raise Exception("Could not get installation id, probably not installed")
def display_directory_tree(
root_path,
includes: list[str] = [],
excludes: list[str] = [".git"],
):
def display_directory_tree_helper(
current_dir,
indent="",
) -> str:
files = os.listdir(current_dir)
files.sort()
tree = ""
for item_name in files:
full_path = os.path.join(current_dir, item_name)[len(root_path) + 1 :]
if item_name in excludes:
continue
file_path = os.path.join(current_dir, item_name)
if os.path.isdir(file_path):
if full_path in includes:
tree += f"{indent}|- {item_name}/\n"
tree += display_directory_tree_helper(
file_path, indent + "| "
)
else:
tree += f"{indent}|- {item_name}/...\n"
else:
tree += f"{indent}|- {item_name}\n"
return tree
tree = display_directory_tree_helper(root_path)
lines = tree.splitlines()
return "\n".join([line[3:] for line in lines])
def get_file_list(root_directory: str) -> str:

"""
This file should be split into environment and config files
"""
PREFIX = "prod"
DB_NAME = PREFIX + "-db"
API_NAME = PREFIX + "-api"
UTILS_NAME = PREFIX + "-utils"
SLACK_NAME = PREFIX + "-slack"
BOT_TOKEN_NAME = PREFIX + "-bot-token"
if PREFIX == "prod":
BOT_TOKEN_NAME = "bot-token"
SWEEP_LOGIN = "sweep-ai[bot]"
if PREFIX == "prod":
APP_ID = 307814
ENV = PREFIX
elif PREFIX == "dev2":
APP_ID = 327588
ENV = PREFIX
SWEEP_LOGIN = "sweep-canary[bot]"
elif PREFIX == "dev":
APP_ID = 324098
ENV = PREFIX
SWEEP_LOGIN = "sweep-nightly[bot]"
LABEL_NAME = "sweep"
LABEL_COLOR = "#9400D3"

'''
On Github ticket, get ChatGPT to deal with it
'''
# TODO: Add file validation
import os
import openai
from loguru import logger
import modal
from sweepai.core.entities import FileChangeRequest, Snippet
from sweepai.core.prompts import (
reply_prompt,
)
from sweepai.core.sweep_bot import SweepBot
from sweepai.core.prompts import issue_comment_prompt
from sweepai.handlers.create_pr import create_pr
from sweepai.handlers.on_comment import on_comment
from sweepai.handlers.on_review import review_pr
from sweepai.utils.event_logger import posthog
from sweepai.utils.github_utils import get_github_client, search_snippets
from sweepai.utils.prompt_constructor import HumanMessagePrompt
from sweepai.utils.constants import DB_NAME, PREFIX, UTILS_NAME
from sweepai.utils.chat_logger import ChatLogger
github_access_token = os.environ.get("GITHUB_TOKEN")
openai.api_key = os.environ.get("OPENAI_API_KEY")
update_index = modal.Function.lookup(DB_NAME, "update_index")
bot_suffix = "I'm a bot that handles simple bugs and feature requests \
but I might make mistakes. Please be kind!"
collapsible_template = '''
<details>
<summary>{summary}</summary>
{body}
</details>
'''
chunker = modal.Function.lookup(UTILS_NAME, "Chunking.chunk")
num_of_snippets_to_query = 30
max_num_of_snippets = 5
def on_ticket(
title: str,
summary: str,
issue_number: int,
issue_url: str,
username: str,
repo_full_name: str,
repo_description: str,
installation_id: int,
comment_id: int = None
):
# Check if the title starts with "sweep" or "sweep: " and remove it
if title.lower().startswith("sweep: "):
title = title[7:]
elif title.lower().startswith("sweep "):
title = title[6:]
# Flow:
# 1. Get relevant files
# 2: Get human message
# 3. Get files to change
# 4. Get file changes
# 5. Create PR
organization, repo_name = repo_full_name.split("/")
metadata = {
"issue_url": issue_url,
"issue_number": issue_number,
"repo_full_name": repo_full_name,
"organization": organization,
"repo_name": repo_name,
"repo_description": repo_description,
"username": username,
"installation_id": installation_id,
"function": "on_ticket",
"mode": PREFIX,
}
posthog.capture(username, "started", properties=metadata)
g = get_github_client(installation_id)
if comment_id:
logger.info(f"Replying to comment {comment_id}...")
logger.info(f"Getting repo {repo_full_name}")
repo = g.get_repo(repo_full_name)
current_issue = repo.get_issue(number=issue_number)
if current_issue.state == 'closed':
posthog.capture(username, "issue_closed", properties=metadata)
return {"success": False, "reason": "Issue is closed"}
item_to_react_to = current_issue.get_comment(comment_id) if comment_id else current_issue


I'm a bot that handles simple bugs and feature requests but I might make mistakes. Please be kind!

@sweep-nightly
Copy link
Contributor

sweep-nightly bot commented Jul 5, 2023

Hey @lukejagg,

I've started working on this PR. Here's a rough summary of my plan:

  1. I'll create a new file sweepai/utils/repo_config.py that will contain a RepoConfig class. This class will handle the loading of settings from the sweep.yaml file.
  2. The RepoConfig class will have a method to read the sweep.yaml file and load the settings.
  3. I'll modify the sweepai/utils/__init__.py file to import the new RepoConfig class so it can be used elsewhere in the codebase.

Give me a minute!

Some code snippets I looked at (click to expand). If some file is missing from here, you can mention the path in the ticket description.

sweep/README.md

Lines 1 to 104 in c23ac48

<p align="center">
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/sweep-banner-github.png">
</p>
<p align="center">
<i>Spend time reviewing code generated by AI, not writing it.</i>
</p>
<p align="center">
<a href="https://sweep.dev/">🌐 Website</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://docs.sweep.dev/">📚 Docs</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://discord.gg/sweep-ai">📢 Discord</a>
</p>
<b>Sweep</b> allows you to create and review GitHub issues with ease.
Simply describe any issue and Sweep will do the rest.
It will plan out what needs to be done, what changes to make, and write the changes to a PR.
Supported languages: Python, Javascript/Typescript, Rust, Go, Java/C#, C++ and anything else GPT-4 supports
---
## ✨ Demo
For the best experience, [install Sweep](https://github.com/apps/sweep-ai) to one of your repos and see the magic happen.
[Demo](https://github.com/sweepai/sweep/assets/44910023/365ec29f-7317-40a7-9b5e-0af02f2b0e47)
## 🚀 Getting Started
### 🖥️ Sweep Chat
Sweep Chat allows you to interact with Sweep locally and will sync with GitHub. You can plan out your changes with Sweep, and then Sweep can create a pull request for you.
1. Install [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Run `pip install sweepai && sweep`. Note that you need python 3.10 or greater.
3. This should spin up a GitHub auth flow in your browser. Copy-paste the 🔵 blue 8-digit code from your terminal into the page. Then wait a few seconds and it should spin up Sweep Chat. You should only need to do the auth once.
4. Pick a repo from the dropdown at the top (the Github app must be installed on this repo). Then start chatting with Sweep Chat. Relevant searched files will show up on the right. Sweep Chat can make PRs if you ask it to create a PR.
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/gradio-screenshot.png">
💡 You can force dark mode by going to http://127.0.0.1:7861/?__theme=dark.
#### From Source
If you want the nightly build and or if the latest build has issues.
1. `git clone https://github.com/sweepai/sweep && poetry install`
2. `python sweepai/app/cli.py`. Note that you need python 3.10 or greater.
### ✨ Sweep Github App
Setting up Sweep is as simple as adding the GitHub bot to a repo, then creating an issue for the bot to address.
1. Add the [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Create new issue in repo, like "Sweep: Write tests"
3. "👀" means it is taking a look, and it will generate the desired code
4. "🚀" means the bot has finished its job and created a PR
## 🤝 Contributing
Contributions are welcome and greatly appreciated! For detailed guidelines on how to contribute, please see the [CONTRIBUTING.md](CONTRIBUTING.md) file. In essence, you'll need to fork the repository, create a new branch for your feature or bug fix, commit your changes, and open a pull request.
For more detailed docs, see [🚀 Quickstart](https://docs.sweep.dev/start).
---
## 📘 Story
We were frustrated by small tickets, like simple bug fixes, annoying refactors, and small features, each task requiring us to open our IDE to fix simple bugs. So, we decided to leverage the capabilities of ChatGPT to address this directly in GitHub.
Unlike existing AI solutions, this can solve entire tickets and can be parallelized: developers can spin up 10 tickets and Sweep will address them all at once.
## 📚 The Stack
- GPT-4 32k 0613 (default) / Claude v1.3 100k
- ActiveLoop DeepLake for Vector DB with MiniLM L12 as our embeddings model
- Modal Labs for infra + deployment
## 🌠 Features
* Automatic feature development
* PR auto self-review + comment handling (effectively [Reflexion](https://arxiv.org/abs/2303.11366))
* Address developer comments after PR is created
* Code snippets embedding-based search
* Chain-of-Thought retrieval using GPT Functions
## 🗺️ Roadmap
We're currently working on responding to linters and external search. For more, see [🗺️ Roadmap](https://docs.sweep.dev/roadmap).
---
<h2 align="center">
Contributors
</h2>
<p align="center">
Thank you for your contribution!
</p>
<p align="center">
<a href="https://github.com/sweepai/sweep/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sweepai/sweep" />
</a>
</p>
<p align="center">
and, of course, Sweep!
</p>

sweep/CONTRIBUTING.md

Lines 1 to 34 in c23ac48

# Contributing to Sweep AI
First off, thank you for considering contributing to Sweep AI. It's people like you that make Sweep AI such a great tool.
## Creating Issues
Before you submit an issue, please do a search in [open issues](https://github.com/sweepai/sweep/issues) to see if the issue or feature request has already been filed.
Use the provided issue template when creating a new issue. Fill in the template with as much detail as possible. The more detail you provide, the more likely that someone can help you.
Alternatively, you can use Sweep to create a ticket for the problem first. Simply describe the issue or feature request, and Sweep will create a ticket for it. This can help you understand the problem better and guide you in manually solving it.
You can also use Sweep to create tickets. Simply describe the issue or feature request, and Sweep will create a ticket for it.
Use the provided issue template when creating a new issue. Fill in the template with as much detail as possible. The more detail you provide, the more likely that someone can help you.
## Submitting Pull Requests
If you're working on an existing issue, respond to the issue and express interest in working on it. This helps other people know that the issue is active, and hopefully prevents duplicated efforts.
To submit a pull request, follow the following steps:
1. Fork the repository.
2. Create a new branch from `main`.
3. Make your changes.
4. Push your branch and submit a pull request to the `main` branch.
5. Await review. Respond to any comments or requests made by reviewers.
## Coding Standards
Please ensure your code adheres to the coding standards used throughout the project. This includes proper indentation, accurate comments, and clear, concise code.
## Community
Please be respectful and considerate of others. We're all here to learn and grow, so constructive, respectful communication is encouraged.

import shutil
import modal
import os
import time
import re
import github
from github import Github
from github.Repository import Repository
from loguru import logger
from jwt import encode
import requests
from tqdm import tqdm
from sweepai.core.entities import Snippet
from sweepai.utils.config import SweepConfig
from sweepai.utils.constants import APP_ID, DB_NAME
from sweepai.utils.event_logger import posthog
def make_valid_string(string: str):
pattern = r"[^\w./-]+"
return re.sub(pattern, "_", string)
def get_jwt():
signing_key = os.environ["GITHUB_APP_PEM"]
app_id = APP_ID
payload = {"iat": int(time.time()), "exp": int(time.time()) + 600, "iss": app_id}
return encode(payload, signing_key, algorithm="RS256")
def get_token(installation_id: int):
jwt = get_jwt()
headers = {
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
}
response = requests.post(
f"https://api.github.com/app/installations/{int(installation_id)}/access_tokens",
headers=headers,
)
return response.json()["token"]
def get_github_client(installation_id: int):
token = get_token(installation_id)
return Github(token)
def get_installation_id(username: str):
jwt = get_jwt()
response = requests.get(
f"https://api.github.com/users/{username}/installation",
headers={
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
},
)
obj = response.json()
try:
return obj["id"]
except:
raise Exception("Could not get installation id, probably not installed")
def display_directory_tree(
root_path,
includes: list[str] = [],
excludes: list[str] = [".git"],
):
def display_directory_tree_helper(
current_dir,
indent="",
) -> str:
files = os.listdir(current_dir)
files.sort()
tree = ""
for item_name in files:
full_path = os.path.join(current_dir, item_name)[len(root_path) + 1 :]
if item_name in excludes:
continue
file_path = os.path.join(current_dir, item_name)
if os.path.isdir(file_path):
if full_path in includes:
tree += f"{indent}|- {item_name}/\n"
tree += display_directory_tree_helper(
file_path, indent + "| "
)
else:
tree += f"{indent}|- {item_name}/...\n"
else:
tree += f"{indent}|- {item_name}\n"
return tree
tree = display_directory_tree_helper(root_path)
lines = tree.splitlines()
return "\n".join([line[3:] for line in lines])
def get_file_list(root_directory: str) -> str:
files = []
def dfs_helper(directory):
nonlocal files
for item in os.listdir(directory):
if item == ".git":
continue
item_path = os.path.join(directory, item)
if os.path.isfile(item_path):
files.append(item_path) # Add the file to the list
elif os.path.isdir(item_path):
dfs_helper(item_path) # Recursive call to explore subdirectory
dfs_helper(root_directory)
files = [file[len(root_directory) + 1 :] for file in files]
return files
# def get_tree(repo_name: str, installation_id: int) -> str:
# token = get_token(installation_id)
# repo_url = f"https://x-access-token:{token}@github.com/{repo_name}.git"
# Repo.clone_from(repo_url, "repo")
# tree = display_directory_tree("repo")
# shutil.rmtree("repo")
# return tree
def get_tree_and_file_list(
repo_name: str,
installation_id: int,
snippet_paths: list[str]
) -> str:
from git import Repo
token = get_token(installation_id)
shutil.rmtree("repo", ignore_errors=True)
repo_url = f"https://x-access-token:{token}@github.com/{repo_name}.git"
Repo.clone_from(repo_url, "repo")
prefixes = []
for snippet_path in snippet_paths:
file_list = ""
for directory in snippet_path.split("/")[:-1]:
file_list += directory + "/"
prefixes.append(file_list.rstrip("/"))
file_list += snippet_path.split("/")[-1]
prefixes.append(snippet_path)
tree = display_directory_tree(
"repo",
includes=prefixes,
)
file_list = get_file_list("repo")
shutil.rmtree("repo")
return tree, file_list
def get_file_contents(repo: Repository, file_path, ref=None):
if ref is None:
ref = repo.default_branch
file = repo.get_contents(file_path, ref=ref)
contents = file.decoded_content.decode("utf-8")
return contents
def search_snippets(
repo: Repository,
query: str,
installation_id: int,
num_files: int = 5,
include_tree: bool = True,
branch: str = None,
sweep_config: SweepConfig = SweepConfig(),
) -> tuple[Snippet, str]:
# Initialize the relevant directories string
get_relevant_snippets = modal.Function.lookup(DB_NAME, "get_relevant_snippets")
snippets: list[Snippet] = get_relevant_snippets.call(
repo.full_name, query, num_files, installation_id=installation_id
)
logger.info(f"Snippets: {snippets}")
for snippet in snippets:
try:
file_contents = get_file_contents(repo, snippet.file_path, ref=branch)
if (
len(file_contents) > sweep_config.max_file_limit
): # more than 10000 tokens
logger.warning(f"Skipping {snippet.file_path}, too many tokens")
continue
except github.UnknownObjectException as e:
logger.warning(f"Error: {e}")
logger.warning(f"Skipping {snippet.file_path}")
else:
snippet.content = file_contents
tree, file_list = get_tree_and_file_list(
repo.full_name,
installation_id,
snippet_paths=[snippet.file_path for snippet in snippets]
)
for file_path in tqdm(file_list):
if file_path in query:
try:
file_contents = get_file_contents(repo, file_path, ref=branch)
if (
len(file_contents) > sweep_config.max_file_limit
): # more than 10000 tokens
logger.warning(f"Skipping {file_path}, too many tokens")
continue
except github.UnknownObjectException as e:
logger.warning(f"Error: {e}")
logger.warning(f"Skipping {file_path}")
else:
snippets.append(
Snippet(
content=file_contents,
start=0,
end=file_contents.count("\n") + 1,
file_path=file_path,
)
)
snippets = [snippet.expand() for snippet in snippets]
if include_tree:
return snippets, tree
else:
return snippets
def index_full_repository(
repo_name: str,
installation_id: int = None,
sweep_config: SweepConfig = SweepConfig(),
):
update_index = modal.Function.lookup(DB_NAME, "update_index")
num_indexed_docs = update_index.spawn(
repo_name=repo_name,
installation_id=installation_id,
sweep_config=sweep_config,
)
try:
repo = get_github_client(installation_id).get_repo(repo_name)
labels = repo.get_labels()
label_names = [label.name for label in labels]
if "sweep" not in label_names:
repo.create_label(
name="sweep",
color="5320E7",
description="Assigns Sweep to an issue or pull request.",
)
except Exception as e:
posthog("index_full_repository", "failed", {"error": str(e)})
logger.warning(
"Adding label failed, probably because label already."
) # warn that the repo may already be indexed
return num_indexed_docs

"""
This file should be split into environment and config files
"""
PREFIX = "prod"
DB_NAME = PREFIX + "-db"
API_NAME = PREFIX + "-api"
UTILS_NAME = PREFIX + "-utils"
SLACK_NAME = PREFIX + "-slack"
BOT_TOKEN_NAME = PREFIX + "-bot-token"
if PREFIX == "prod":
BOT_TOKEN_NAME = "bot-token"
SWEEP_LOGIN = "sweep-ai[bot]"
if PREFIX == "prod":
APP_ID = 307814
ENV = PREFIX
elif PREFIX == "dev2":
APP_ID = 327588
ENV = PREFIX
SWEEP_LOGIN = "sweep-canary[bot]"
elif PREFIX == "dev":
APP_ID = 324098
ENV = PREFIX
SWEEP_LOGIN = "sweep-nightly[bot]"
LABEL_NAME = "sweep"
LABEL_COLOR = "#9400D3"

'''
On Github ticket, get ChatGPT to deal with it
'''
# TODO: Add file validation
import os
import openai
from loguru import logger
import modal
from sweepai.core.entities import FileChangeRequest, Snippet
from sweepai.core.prompts import (
reply_prompt,
)
from sweepai.core.sweep_bot import SweepBot
from sweepai.core.prompts import issue_comment_prompt
from sweepai.handlers.create_pr import create_pr
from sweepai.handlers.on_comment import on_comment
from sweepai.handlers.on_review import review_pr
from sweepai.utils.event_logger import posthog
from sweepai.utils.github_utils import get_github_client, search_snippets
from sweepai.utils.prompt_constructor import HumanMessagePrompt
from sweepai.utils.constants import DB_NAME, PREFIX, UTILS_NAME
from sweepai.utils.chat_logger import ChatLogger
github_access_token = os.environ.get("GITHUB_TOKEN")
openai.api_key = os.environ.get("OPENAI_API_KEY")
update_index = modal.Function.lookup(DB_NAME, "update_index")
bot_suffix = "I'm a bot that handles simple bugs and feature requests \
but I might make mistakes. Please be kind!"
collapsible_template = '''
<details>
<summary>{summary}</summary>
{body}
</details>
'''
chunker = modal.Function.lookup(UTILS_NAME, "Chunking.chunk")
num_of_snippets_to_query = 30
max_num_of_snippets = 5
def on_ticket(
title: str,
summary: str,
issue_number: int,
issue_url: str,
username: str,
repo_full_name: str,
repo_description: str,
installation_id: int,
comment_id: int = None
):
# Check if the title starts with "sweep" or "sweep: " and remove it
if title.lower().startswith("sweep: "):
title = title[7:]
elif title.lower().startswith("sweep "):
title = title[6:]
# Flow:
# 1. Get relevant files
# 2: Get human message
# 3. Get files to change
# 4. Get file changes
# 5. Create PR
organization, repo_name = repo_full_name.split("/")
metadata = {
"issue_url": issue_url,
"issue_number": issue_number,
"repo_full_name": repo_full_name,
"organization": organization,
"repo_name": repo_name,
"repo_description": repo_description,
"username": username,
"installation_id": installation_id,
"function": "on_ticket",
"mode": PREFIX,
}
posthog.capture(username, "started", properties=metadata)
g = get_github_client(installation_id)
if comment_id:
logger.info(f"Replying to comment {comment_id}...")
logger.info(f"Getting repo {repo_full_name}")
repo = g.get_repo(repo_full_name)
current_issue = repo.get_issue(number=issue_number)
if current_issue.state == 'closed':
posthog.capture(username, "issue_closed", properties=metadata)
return {"success": False, "reason": "Issue is closed"}
item_to_react_to = current_issue.get_comment(comment_id) if comment_id else current_issue


I'm a bot that handles simple bugs and feature requests but I might make mistakes. Please be kind!

@lukejagg lukejagg added sweep Assigns Sweep to an issue or pull request. and removed sweep Assigns Sweep to an issue or pull request. labels Jul 5, 2023
@sweep-nightly
Copy link
Contributor

sweep-nightly bot commented Jul 5, 2023

Hey @lukejagg! 👋

I've started working on your PR to add the repo_config.py file. Here's a rough summary of my plan:


💡 I'll create the following PR:

Add repo config file

I'll create a new file called repo_config.py in the sweepai/utils directory. This file will contain the RepoConfig class that reads the sweep.yaml file and loads the settings into the class.

Here is my plan:

  • Create the repo_config.py file in the sweepai/utils directory.
  • Implement the RepoConfig class that reads the sweep.yaml file and loads the settings.

Reply with "ok" to create the PR or anything else to propose changes.


Give me a minute! 😊

Some code snippets I looked at (click to expand). If some file is missing from here, you can mention the path in the ticket description.

sweep/README.md

Lines 1 to 104 in c23ac48

<p align="center">
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/sweep-banner-github.png">
</p>
<p align="center">
<i>Spend time reviewing code generated by AI, not writing it.</i>
</p>
<p align="center">
<a href="https://sweep.dev/">🌐 Website</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://docs.sweep.dev/">📚 Docs</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://discord.gg/sweep-ai">📢 Discord</a>
</p>
<b>Sweep</b> allows you to create and review GitHub issues with ease.
Simply describe any issue and Sweep will do the rest.
It will plan out what needs to be done, what changes to make, and write the changes to a PR.
Supported languages: Python, Javascript/Typescript, Rust, Go, Java/C#, C++ and anything else GPT-4 supports
---
## ✨ Demo
For the best experience, [install Sweep](https://github.com/apps/sweep-ai) to one of your repos and see the magic happen.
[Demo](https://github.com/sweepai/sweep/assets/44910023/365ec29f-7317-40a7-9b5e-0af02f2b0e47)
## 🚀 Getting Started
### 🖥️ Sweep Chat
Sweep Chat allows you to interact with Sweep locally and will sync with GitHub. You can plan out your changes with Sweep, and then Sweep can create a pull request for you.
1. Install [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Run `pip install sweepai && sweep`. Note that you need python 3.10 or greater.
3. This should spin up a GitHub auth flow in your browser. Copy-paste the 🔵 blue 8-digit code from your terminal into the page. Then wait a few seconds and it should spin up Sweep Chat. You should only need to do the auth once.
4. Pick a repo from the dropdown at the top (the Github app must be installed on this repo). Then start chatting with Sweep Chat. Relevant searched files will show up on the right. Sweep Chat can make PRs if you ask it to create a PR.
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/gradio-screenshot.png">
💡 You can force dark mode by going to http://127.0.0.1:7861/?__theme=dark.
#### From Source
If you want the nightly build and or if the latest build has issues.
1. `git clone https://github.com/sweepai/sweep && poetry install`
2. `python sweepai/app/cli.py`. Note that you need python 3.10 or greater.
### ✨ Sweep Github App
Setting up Sweep is as simple as adding the GitHub bot to a repo, then creating an issue for the bot to address.
1. Add the [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Create new issue in repo, like "Sweep: Write tests"
3. "👀" means it is taking a look, and it will generate the desired code
4. "🚀" means the bot has finished its job and created a PR
## 🤝 Contributing
Contributions are welcome and greatly appreciated! For detailed guidelines on how to contribute, please see the [CONTRIBUTING.md](CONTRIBUTING.md) file. In essence, you'll need to fork the repository, create a new branch for your feature or bug fix, commit your changes, and open a pull request.
For more detailed docs, see [🚀 Quickstart](https://docs.sweep.dev/start).
---
## 📘 Story
We were frustrated by small tickets, like simple bug fixes, annoying refactors, and small features, each task requiring us to open our IDE to fix simple bugs. So, we decided to leverage the capabilities of ChatGPT to address this directly in GitHub.
Unlike existing AI solutions, this can solve entire tickets and can be parallelized: developers can spin up 10 tickets and Sweep will address them all at once.
## 📚 The Stack
- GPT-4 32k 0613 (default) / Claude v1.3 100k
- ActiveLoop DeepLake for Vector DB with MiniLM L12 as our embeddings model
- Modal Labs for infra + deployment
## 🌠 Features
* Automatic feature development
* PR auto self-review + comment handling (effectively [Reflexion](https://arxiv.org/abs/2303.11366))
* Address developer comments after PR is created
* Code snippets embedding-based search
* Chain-of-Thought retrieval using GPT Functions
## 🗺️ Roadmap
We're currently working on responding to linters and external search. For more, see [🗺️ Roadmap](https://docs.sweep.dev/roadmap).
---
<h2 align="center">
Contributors
</h2>
<p align="center">
Thank you for your contribution!
</p>
<p align="center">
<a href="https://github.com/sweepai/sweep/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sweepai/sweep" />
</a>
</p>
<p align="center">
and, of course, Sweep!
</p>

import shutil
import modal
import os
import time
import re
import github
from github import Github
from github.Repository import Repository
from loguru import logger
from jwt import encode
import requests
from tqdm import tqdm
from sweepai.core.entities import Snippet
from sweepai.utils.config import SweepConfig
from sweepai.utils.constants import APP_ID, DB_NAME
from sweepai.utils.event_logger import posthog
def make_valid_string(string: str):
pattern = r"[^\w./-]+"
return re.sub(pattern, "_", string)
def get_jwt():
signing_key = os.environ["GITHUB_APP_PEM"]
app_id = APP_ID
payload = {"iat": int(time.time()), "exp": int(time.time()) + 600, "iss": app_id}
return encode(payload, signing_key, algorithm="RS256")
def get_token(installation_id: int):
jwt = get_jwt()
headers = {
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
}
response = requests.post(
f"https://api.github.com/app/installations/{int(installation_id)}/access_tokens",
headers=headers,
)
return response.json()["token"]
def get_github_client(installation_id: int):
token = get_token(installation_id)
return Github(token)
def get_installation_id(username: str):
jwt = get_jwt()
response = requests.get(
f"https://api.github.com/users/{username}/installation",
headers={
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
},
)
obj = response.json()
try:
return obj["id"]
except:
raise Exception("Could not get installation id, probably not installed")
def display_directory_tree(
root_path,
includes: list[str] = [],
excludes: list[str] = [".git"],
):
def display_directory_tree_helper(
current_dir,
indent="",
) -> str:
files = os.listdir(current_dir)
files.sort()
tree = ""
for item_name in files:
full_path = os.path.join(current_dir, item_name)[len(root_path) + 1 :]
if item_name in excludes:
continue
file_path = os.path.join(current_dir, item_name)
if os.path.isdir(file_path):
if full_path in includes:
tree += f"{indent}|- {item_name}/\n"
tree += display_directory_tree_helper(
file_path, indent + "| "
)
else:
tree += f"{indent}|- {item_name}/...\n"
else:
tree += f"{indent}|- {item_name}\n"
return tree
tree = display_directory_tree_helper(root_path)
lines = tree.splitlines()
return "\n".join([line[3:] for line in lines])
def get_file_list(root_directory: str) -> str:

sweep/sweepai/events.py

Lines 1 to 109 in c23ac48

from typing import Literal
from pydantic import BaseModel
class Installation(BaseModel):
id: str
class InstallationCreatedRequest(BaseModel):
class Repository(BaseModel):
full_name: str
repositories: list[Repository]
installation: Installation
class ReposAddedRequest(BaseModel):
class Repository(BaseModel):
full_name: str
repositories_added: list[Repository]
installation: Installation
class CommentCreatedRequest(BaseModel):
class Comment(BaseModel):
class User(BaseModel):
login: str
body: str | None
original_line: int
path: str
diff_hunk: str
user: User
class PullRequest(BaseModel):
class Head(BaseModel):
ref: str
number: int
body: str | None
state: str # "closed" or "open"
head: Head
title: str
class Repository(BaseModel):
full_name: str
description: str | None
class Sender(BaseModel):
pass
action: str
comment: Comment
pull_request: PullRequest
repository: Repository
sender: Sender
installation: Installation
class IssueRequest(BaseModel):
class Issue(BaseModel):
class User(BaseModel):
login: str
type: str
class Assignee(BaseModel):
login: str
class Repository(BaseModel):
# TODO(sweep): Move this out
full_name: str
description: str | None
class Label(BaseModel):
name: str
class PullRequest(BaseModel):
pass
pull_request: PullRequest | None
title: str
number: int
html_url: str
user: User
body: str | None
labels: list[Label]
assignees: list[Assignee]
action: str
issue: Issue
repository: Issue.Repository
assignee: Issue.Assignee | None
installation: Installation
class IssueCommentRequest(IssueRequest):
class Comment(BaseModel):
class User(BaseModel):
login: str
type: Literal["User", "Bot"]
user: User
id: int
body: str
comment: Comment
class PRRequest(BaseModel):
class PullRequest(BaseModel):
class User(BaseModel):
login: str
class MergedBy(BaseModel):
login: str
user: User
merged_by: MergedBy
class Repository(BaseModel):
full_name: str
pull_request: PullRequest

sweep/tests/test_diffs.py

Lines 506 to 738 in c23ac48

# # Initialize the model
# init_model()
# # Train the model
# train_model()
# if __name__ == "__main__":
# main()
# ```
# """
# print(format_contents(test_file))
# test_file = """```python
# import torch
# import torchvision
# import torchvision.transforms as transforms
# def load_data():
# # Load the training and testing data
# # This is just a placeholder and should be replaced with your actual data loading code
# pass
# def init_model():
# # Initialize the model
# # This is just a placeholder and should be replaced with your actual model initialization code
# pass
# reg = ```abc```
# def train_model():
# # Train the model
# # This is just a placeholder and should be replaced with your actual model training code
# pass
# def main():
# # Load the data
# load_data()
# # Initialize the model
# init_model()
# # Train the model
# train_model()
# if __name__ == "__main__":
# main()
# ```
# """
# print(format_contents(test_file))
test_file = """
test.py
```python
import json
from github import Github
import gradio as gr
from loguru import logger
import webbrowser
from gradio import Button
from sweepai.app.api_client import APIClient, create_pr_function, create_pr_function_call
from sweepai.app.config import SweepChatConfig
from sweepai.core.entities import Snippet
config = SweepChatConfig.load()
api_client = APIClient(config=config)
pr_summary_template = '''💡 I'll create the following PR:
**{title}**
{summary}
Here is my plan:
{plan}
Reply with "ok" to create the PR or anything else to propose changes.'''
github_client = Github(config.github_pat)
repos = list(github_client.get_user().get_repos())
css = '''
footer {
visibility: hidden;
}
pre, code {
white-space: pre-wrap !important;
word-break: break-all !important;
}
#snippets {
height: 750px;
overflow-y: scroll;
}
'''
def get_files_recursively(repo, path=''):
path_to_contents = {}
try:
contents = repo.get_contents(path)
files = []
while contents:
file_content = contents.pop(0)
if file_content.type == 'dir':
contents.extend(repo.get_contents(file_content.path))
else:
try:
decoded_contents = file_content.decoded_content.decode("utf-8")
except:
continue
if decoded_contents:
path_to_contents[file_content.path] = file_content.decoded_content.decode("utf-8")
files.append(file_content.path)
return sorted(files), path_to_contents
except Exception as e:
logger.error(e)
return [], path_to_contents
def create_pr_button_click():
global proposed_pr
if proposed_pr:
chat_history = [[None, f"⏳ Creating PR..."]]
pull_request = api_client.create_pr(
file_change_requests=[(item["file_path"], item["instructions"]) for item in proposed_pr["plan"]],
pull_request={
"title": proposed_pr["title"],
"content": proposed_pr["summary"],
"branch_name": proposed_pr["branch"],
},
messages=chat_history,
)
chat_history[-1][1] = f"✅ PR created at {pull_request['html_url']}"
return chat_history
with gr.Blocks(theme=gr.themes.Soft(), title="Sweep Chat", css=css) as demo:
with gr.Row():
with gr.Column():
repo_full_name = gr.Dropdown(choices=[repo.full_name for repo in repos], label="Repo full name", value=config.repo_full_name or "")
with gr.Column(scale=2):
repo = github_client.get_repo(config.repo_full_name)
all_files, path_to_contents = get_files_recursively(repo)
file_names = gr.Dropdown(choices=all_files, multiselect=True, label="Files")
with gr.Row():
with gr.Column(scale=2):
chatbot = gr.Chatbot(height=750)
with gr.Column():
snippets_text = gr.Markdown(value="### Relevant snippets", elem_id="snippets")
create_pr_button = Button("Create PR", create_pr_button_click)
msg = gr.Textbox(label="Message to Sweep", placeholder="Write unit tests for OpenAI calls")
# clear = gr.ClearButton([msg, chatbot, snippets_text])
proposed_pr: str | None = None
searched = False
selected_snippets = []
file_to_str = {}
def repo_name_change(repo_full_name):
global installation_id
try:
config.repo_full_name = repo_full_name
api_client.config = config
installation_id = api_client.get_installation_id()
assert installation_id
config.installation_id = installation_id
api_client.config = config
config.save()
return ""
except Exception as e:
webbrowser.open_new_tab("https://github.com/apps/sweep-ai")
config.repo_full_name = None
config.installation_id = None
config.save()
api_client.config = config
raise e
repo_full_name.change(repo_name_change, [repo_full_name], [msg])
def build_string():
global selected_snippets
global file_to_str
for snippet in selected_snippets:
file_name = snippet.file_path
if file_name not in file_to_str:
add_file_to_dict(file_name)
snippets_text = "### Relevant snippets:\n" + "\n\n".join([file_to_str[snippet.file_path] for snippet in selected_snippets])
return snippets_text
def add_file_to_dict(file_name):
global file_to_str
global path_to_contents
if file_name in path_to_contents:
file_contents = path_to_contents[file_name]
else:
file_contents = repo.get_contents(file_name).decoded_content.decode('utf-8')
file_contents_split = file_contents.split("\n")
length = len(file_contents_split)
backtick, escaped_backtick = "`", "\\`"
preview = "\n".join(file_contents_split[:3]).replace(backtick, escaped_backtick)
file_to_str[file_name] = f'{file_name}:0:{length}\n```python\n{preview}\n...\n```'
def file_names_change(file_names):
global selected_snippets
global file_to_str
global path_to_contents
selected_snippets = [Snippet(content=path_to_contents[file_name], start=0, end=path_to_contents[file_name].count('\n'), file_path=file_name) for file_name in file_names]
return file_names, build_string()
file_names.change(file_names_change, [file_names], [file_names, snippets_text])
def handle_message_submit(repo_full_name: str, user_message: str, history: list[tuple[str | None, str | None]]):
if not repo_full_name:
raise Exception("Set the repository name first")
return gr.update(value="", interactive=False), history + [[user_message, None]]
def handle_message_stream(chat_history: list[tuple[str | None, str | None]], snippets_text, file_names):
global selected_snippets
global searched
message = chat_history[-1][0]
yield chat_history, snippets_text, file_names
if not selected_snippets:
searched = True
# Searching for relevant snippets
chat_history[-1][1] = "Searching for relevant snippets..."
snippets_text = build_string()
yield chat_history, snippets_text, file_names
logger.info("Fetching relevant snippets...")
selected_snippets += api_client.search(chat_history[-1][0], 3)
snippets_text = build_string()
file_names = [snippet.file_path for snippet in selected_snippets]
yield chat_history, snippets_text, file_names
logger.info("Fetched relevant snippets.")
chat_history[-1][1] = "Found relevant snippets."
# Update using chat_history
snippets_text = build_string()

from typing import Any
import webbrowser
import httpx
from pydantic import BaseModel
import requests
import json
from loguru import logger
from sweepai.app.config import SweepChatConfig
from sweepai.core.entities import Function, PullRequest, Snippet
from sweepai.utils.constants import PREFIX
create_pr_function = Function(
name="create_pr",
description="Creates a PR.",
parameters={
"properties": {
"plan": {
"type": "array",
"items": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "The file path to change."
},
"instructions": {
"type": "string",
"description": "Concise NATURAL LANGUAGE summary of what to change in each file. There should be absolutely NO code, only English.",
"example": [
"Refactor the algorithm by moving the main function to the top of the file.",
"Change the implementation to recursion"
]
},
},
"required": ["file_path", "instructions"]
},
"description": "A list of files to modify or create and corresponding instructions."
},
"title": {
"type": "string",
"description": "Title of PR",
},
"summary": {
"type": "string",
"description": "Detailed summary of PR",
},
"branch": {
"type": "string",
"description": "Name of branch to create PR in.",
},
},
"required": ["plan", "title", "summary", "branch"]
}
)
create_pr_function_call = {"name": "create_pr"}
def break_json(raw_json: str):
# turns something like {"function_call": {"arguments": " \""}}{"function_call": {"arguments": "summary"}} into two objects
try:
yield json.loads(raw_json)


I'm a bot that handles simple bugs and feature requests but I might make mistakes. Please be kind!

@sweep-ai
Copy link
Contributor

sweep-ai bot commented Jul 5, 2023

Hey @lukejagg,

I've started working on this PR. Here's a rough summary of the plan:

  1. Create a new file named repo_config.py in the sweepai/utils/ directory.
  2. In this file, define a class RepoConfig that will handle the loading of settings from a sweep.yaml file in a given repository.
  3. The RepoConfig class will have an __init__ method that accepts a repo of type Repository.
  4. The RepoConfig class will also have a load_config method that reads the sweep.yaml file from the given repository and loads the settings into the class.
  5. Handle potential errors when reading the sweep.yaml file.

Give me a minute!

Some code snippets I looked at (click to expand). If some file is missing from here, you can mention the path in the ticket description.

sweep/README.md

Lines 1 to 104 in c23ac48

<p align="center">
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/sweep-banner-github.png">
</p>
<p align="center">
<i>Spend time reviewing code generated by AI, not writing it.</i>
</p>
<p align="center">
<a href="https://sweep.dev/">🌐 Website</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://docs.sweep.dev/">📚 Docs</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://discord.gg/sweep-ai">📢 Discord</a>
</p>
<b>Sweep</b> allows you to create and review GitHub issues with ease.
Simply describe any issue and Sweep will do the rest.
It will plan out what needs to be done, what changes to make, and write the changes to a PR.
Supported languages: Python, Javascript/Typescript, Rust, Go, Java/C#, C++ and anything else GPT-4 supports
---
## ✨ Demo
For the best experience, [install Sweep](https://github.com/apps/sweep-ai) to one of your repos and see the magic happen.
[Demo](https://github.com/sweepai/sweep/assets/44910023/365ec29f-7317-40a7-9b5e-0af02f2b0e47)
## 🚀 Getting Started
### 🖥️ Sweep Chat
Sweep Chat allows you to interact with Sweep locally and will sync with GitHub. You can plan out your changes with Sweep, and then Sweep can create a pull request for you.
1. Install [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Run `pip install sweepai && sweep`. Note that you need python 3.10 or greater.
3. This should spin up a GitHub auth flow in your browser. Copy-paste the 🔵 blue 8-digit code from your terminal into the page. Then wait a few seconds and it should spin up Sweep Chat. You should only need to do the auth once.
4. Pick a repo from the dropdown at the top (the Github app must be installed on this repo). Then start chatting with Sweep Chat. Relevant searched files will show up on the right. Sweep Chat can make PRs if you ask it to create a PR.
<img src="https://github.com/sweepai/sweep/blob/856ff66c2dbeaf39afbf6d8c49a620dfa70271fb/.assets/gradio-screenshot.png">
💡 You can force dark mode by going to http://127.0.0.1:7861/?__theme=dark.
#### From Source
If you want the nightly build and or if the latest build has issues.
1. `git clone https://github.com/sweepai/sweep && poetry install`
2. `python sweepai/app/cli.py`. Note that you need python 3.10 or greater.
### ✨ Sweep Github App
Setting up Sweep is as simple as adding the GitHub bot to a repo, then creating an issue for the bot to address.
1. Add the [Sweep GitHub app](https://github.com/apps/sweep-ai) to desired repos
2. Create new issue in repo, like "Sweep: Write tests"
3. "👀" means it is taking a look, and it will generate the desired code
4. "🚀" means the bot has finished its job and created a PR
## 🤝 Contributing
Contributions are welcome and greatly appreciated! For detailed guidelines on how to contribute, please see the [CONTRIBUTING.md](CONTRIBUTING.md) file. In essence, you'll need to fork the repository, create a new branch for your feature or bug fix, commit your changes, and open a pull request.
For more detailed docs, see [🚀 Quickstart](https://docs.sweep.dev/start).
---
## 📘 Story
We were frustrated by small tickets, like simple bug fixes, annoying refactors, and small features, each task requiring us to open our IDE to fix simple bugs. So, we decided to leverage the capabilities of ChatGPT to address this directly in GitHub.
Unlike existing AI solutions, this can solve entire tickets and can be parallelized: developers can spin up 10 tickets and Sweep will address them all at once.
## 📚 The Stack
- GPT-4 32k 0613 (default) / Claude v1.3 100k
- ActiveLoop DeepLake for Vector DB with MiniLM L12 as our embeddings model
- Modal Labs for infra + deployment
## 🌠 Features
* Automatic feature development
* PR auto self-review + comment handling (effectively [Reflexion](https://arxiv.org/abs/2303.11366))
* Address developer comments after PR is created
* Code snippets embedding-based search
* Chain-of-Thought retrieval using GPT Functions
## 🗺️ Roadmap
We're currently working on responding to linters and external search. For more, see [🗺️ Roadmap](https://docs.sweep.dev/roadmap).
---
<h2 align="center">
Contributors
</h2>
<p align="center">
Thank you for your contribution!
</p>
<p align="center">
<a href="https://github.com/sweepai/sweep/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sweepai/sweep" />
</a>
</p>
<p align="center">
and, of course, Sweep!
</p>

import shutil
import modal
import os
import time
import re
import github
from github import Github
from github.Repository import Repository
from loguru import logger
from jwt import encode
import requests
from tqdm import tqdm
from sweepai.core.entities import Snippet
from sweepai.utils.config import SweepConfig
from sweepai.utils.constants import APP_ID, DB_NAME
from sweepai.utils.event_logger import posthog
def make_valid_string(string: str):
pattern = r"[^\w./-]+"
return re.sub(pattern, "_", string)
def get_jwt():
signing_key = os.environ["GITHUB_APP_PEM"]
app_id = APP_ID
payload = {"iat": int(time.time()), "exp": int(time.time()) + 600, "iss": app_id}
return encode(payload, signing_key, algorithm="RS256")
def get_token(installation_id: int):
jwt = get_jwt()
headers = {
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
}
response = requests.post(
f"https://api.github.com/app/installations/{int(installation_id)}/access_tokens",
headers=headers,
)
return response.json()["token"]
def get_github_client(installation_id: int):
token = get_token(installation_id)
return Github(token)
def get_installation_id(username: str):
jwt = get_jwt()
response = requests.get(
f"https://api.github.com/users/{username}/installation",
headers={
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + jwt,
"X-GitHub-Api-Version": "2022-11-28",
},
)
obj = response.json()
try:
return obj["id"]
except:
raise Exception("Could not get installation id, probably not installed")
def display_directory_tree(
root_path,
includes: list[str] = [],
excludes: list[str] = [".git"],
):
def display_directory_tree_helper(
current_dir,
indent="",
) -> str:
files = os.listdir(current_dir)
files.sort()
tree = ""
for item_name in files:
full_path = os.path.join(current_dir, item_name)[len(root_path) + 1 :]
if item_name in excludes:
continue
file_path = os.path.join(current_dir, item_name)
if os.path.isdir(file_path):
if full_path in includes:
tree += f"{indent}|- {item_name}/\n"
tree += display_directory_tree_helper(
file_path, indent + "| "
)
else:
tree += f"{indent}|- {item_name}/...\n"
else:
tree += f"{indent}|- {item_name}\n"
return tree
tree = display_directory_tree_helper(root_path)
lines = tree.splitlines()
return "\n".join([line[3:] for line in lines])
def get_file_list(root_directory: str) -> str:

sweep/sweepai/events.py

Lines 1 to 109 in c23ac48

from typing import Literal
from pydantic import BaseModel
class Installation(BaseModel):
id: str
class InstallationCreatedRequest(BaseModel):
class Repository(BaseModel):
full_name: str
repositories: list[Repository]
installation: Installation
class ReposAddedRequest(BaseModel):
class Repository(BaseModel):
full_name: str
repositories_added: list[Repository]
installation: Installation
class CommentCreatedRequest(BaseModel):
class Comment(BaseModel):
class User(BaseModel):
login: str
body: str | None
original_line: int
path: str
diff_hunk: str
user: User
class PullRequest(BaseModel):
class Head(BaseModel):
ref: str
number: int
body: str | None
state: str # "closed" or "open"
head: Head
title: str
class Repository(BaseModel):
full_name: str
description: str | None
class Sender(BaseModel):
pass
action: str
comment: Comment
pull_request: PullRequest
repository: Repository
sender: Sender
installation: Installation
class IssueRequest(BaseModel):
class Issue(BaseModel):
class User(BaseModel):
login: str
type: str
class Assignee(BaseModel):
login: str
class Repository(BaseModel):
# TODO(sweep): Move this out
full_name: str
description: str | None
class Label(BaseModel):
name: str
class PullRequest(BaseModel):
pass
pull_request: PullRequest | None
title: str
number: int
html_url: str
user: User
body: str | None
labels: list[Label]
assignees: list[Assignee]
action: str
issue: Issue
repository: Issue.Repository
assignee: Issue.Assignee | None
installation: Installation
class IssueCommentRequest(IssueRequest):
class Comment(BaseModel):
class User(BaseModel):
login: str
type: Literal["User", "Bot"]
user: User
id: int
body: str
comment: Comment
class PRRequest(BaseModel):
class PullRequest(BaseModel):
class User(BaseModel):
login: str
class MergedBy(BaseModel):
login: str
user: User
merged_by: MergedBy
class Repository(BaseModel):
full_name: str
pull_request: PullRequest

sweep/tests/test_diffs.py

Lines 506 to 738 in c23ac48

# # Initialize the model
# init_model()
# # Train the model
# train_model()
# if __name__ == "__main__":
# main()
# ```
# """
# print(format_contents(test_file))
# test_file = """```python
# import torch
# import torchvision
# import torchvision.transforms as transforms
# def load_data():
# # Load the training and testing data
# # This is just a placeholder and should be replaced with your actual data loading code
# pass
# def init_model():
# # Initialize the model
# # This is just a placeholder and should be replaced with your actual model initialization code
# pass
# reg = ```abc```
# def train_model():
# # Train the model
# # This is just a placeholder and should be replaced with your actual model training code
# pass
# def main():
# # Load the data
# load_data()
# # Initialize the model
# init_model()
# # Train the model
# train_model()
# if __name__ == "__main__":
# main()
# ```
# """
# print(format_contents(test_file))
test_file = """
test.py
```python
import json
from github import Github
import gradio as gr
from loguru import logger
import webbrowser
from gradio import Button
from sweepai.app.api_client import APIClient, create_pr_function, create_pr_function_call
from sweepai.app.config import SweepChatConfig
from sweepai.core.entities import Snippet
config = SweepChatConfig.load()
api_client = APIClient(config=config)
pr_summary_template = '''💡 I'll create the following PR:
**{title}**
{summary}
Here is my plan:
{plan}
Reply with "ok" to create the PR or anything else to propose changes.'''
github_client = Github(config.github_pat)
repos = list(github_client.get_user().get_repos())
css = '''
footer {
visibility: hidden;
}
pre, code {
white-space: pre-wrap !important;
word-break: break-all !important;
}
#snippets {
height: 750px;
overflow-y: scroll;
}
'''
def get_files_recursively(repo, path=''):
path_to_contents = {}
try:
contents = repo.get_contents(path)
files = []
while contents:
file_content = contents.pop(0)
if file_content.type == 'dir':
contents.extend(repo.get_contents(file_content.path))
else:
try:
decoded_contents = file_content.decoded_content.decode("utf-8")
except:
continue
if decoded_contents:
path_to_contents[file_content.path] = file_content.decoded_content.decode("utf-8")
files.append(file_content.path)
return sorted(files), path_to_contents
except Exception as e:
logger.error(e)
return [], path_to_contents
def create_pr_button_click():
global proposed_pr
if proposed_pr:
chat_history = [[None, f"⏳ Creating PR..."]]
pull_request = api_client.create_pr(
file_change_requests=[(item["file_path"], item["instructions"]) for item in proposed_pr["plan"]],
pull_request={
"title": proposed_pr["title"],
"content": proposed_pr["summary"],
"branch_name": proposed_pr["branch"],
},
messages=chat_history,
)
chat_history[-1][1] = f"✅ PR created at {pull_request['html_url']}"
return chat_history
with gr.Blocks(theme=gr.themes.Soft(), title="Sweep Chat", css=css) as demo:
with gr.Row():
with gr.Column():
repo_full_name = gr.Dropdown(choices=[repo.full_name for repo in repos], label="Repo full name", value=config.repo_full_name or "")
with gr.Column(scale=2):
repo = github_client.get_repo(config.repo_full_name)
all_files, path_to_contents = get_files_recursively(repo)
file_names = gr.Dropdown(choices=all_files, multiselect=True, label="Files")
with gr.Row():
with gr.Column(scale=2):
chatbot = gr.Chatbot(height=750)
with gr.Column():
snippets_text = gr.Markdown(value="### Relevant snippets", elem_id="snippets")
create_pr_button = Button("Create PR", create_pr_button_click)
msg = gr.Textbox(label="Message to Sweep", placeholder="Write unit tests for OpenAI calls")
# clear = gr.ClearButton([msg, chatbot, snippets_text])
proposed_pr: str | None = None
searched = False
selected_snippets = []
file_to_str = {}
def repo_name_change(repo_full_name):
global installation_id
try:
config.repo_full_name = repo_full_name
api_client.config = config
installation_id = api_client.get_installation_id()
assert installation_id
config.installation_id = installation_id
api_client.config = config
config.save()
return ""
except Exception as e:
webbrowser.open_new_tab("https://github.com/apps/sweep-ai")
config.repo_full_name = None
config.installation_id = None
config.save()
api_client.config = config
raise e
repo_full_name.change(repo_name_change, [repo_full_name], [msg])
def build_string():
global selected_snippets
global file_to_str
for snippet in selected_snippets:
file_name = snippet.file_path
if file_name not in file_to_str:
add_file_to_dict(file_name)
snippets_text = "### Relevant snippets:\n" + "\n\n".join([file_to_str[snippet.file_path] for snippet in selected_snippets])
return snippets_text
def add_file_to_dict(file_name):
global file_to_str
global path_to_contents
if file_name in path_to_contents:
file_contents = path_to_contents[file_name]
else:
file_contents = repo.get_contents(file_name).decoded_content.decode('utf-8')
file_contents_split = file_contents.split("\n")
length = len(file_contents_split)
backtick, escaped_backtick = "`", "\\`"
preview = "\n".join(file_contents_split[:3]).replace(backtick, escaped_backtick)
file_to_str[file_name] = f'{file_name}:0:{length}\n```python\n{preview}\n...\n```'
def file_names_change(file_names):
global selected_snippets
global file_to_str
global path_to_contents
selected_snippets = [Snippet(content=path_to_contents[file_name], start=0, end=path_to_contents[file_name].count('\n'), file_path=file_name) for file_name in file_names]
return file_names, build_string()
file_names.change(file_names_change, [file_names], [file_names, snippets_text])
def handle_message_submit(repo_full_name: str, user_message: str, history: list[tuple[str | None, str | None]]):
if not repo_full_name:
raise Exception("Set the repository name first")
return gr.update(value="", interactive=False), history + [[user_message, None]]
def handle_message_stream(chat_history: list[tuple[str | None, str | None]], snippets_text, file_names):
global selected_snippets
global searched
message = chat_history[-1][0]
yield chat_history, snippets_text, file_names
if not selected_snippets:
searched = True
# Searching for relevant snippets
chat_history[-1][1] = "Searching for relevant snippets..."
snippets_text = build_string()
yield chat_history, snippets_text, file_names
logger.info("Fetching relevant snippets...")
selected_snippets += api_client.search(chat_history[-1][0], 3)
snippets_text = build_string()
file_names = [snippet.file_path for snippet in selected_snippets]
yield chat_history, snippets_text, file_names
logger.info("Fetched relevant snippets.")
chat_history[-1][1] = "Found relevant snippets."
# Update using chat_history
snippets_text = build_string()

from typing import Any
import webbrowser
import httpx
from pydantic import BaseModel
import requests
import json
from loguru import logger
from sweepai.app.config import SweepChatConfig
from sweepai.core.entities import Function, PullRequest, Snippet
from sweepai.utils.constants import PREFIX
create_pr_function = Function(
name="create_pr",
description="Creates a PR.",
parameters={
"properties": {
"plan": {
"type": "array",
"items": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "The file path to change."
},
"instructions": {
"type": "string",
"description": "Concise NATURAL LANGUAGE summary of what to change in each file. There should be absolutely NO code, only English.",
"example": [
"Refactor the algorithm by moving the main function to the top of the file.",
"Change the implementation to recursion"
]
},
},
"required": ["file_path", "instructions"]
},
"description": "A list of files to modify or create and corresponding instructions."
},
"title": {
"type": "string",
"description": "Title of PR",
},
"summary": {
"type": "string",
"description": "Detailed summary of PR",
},
"branch": {
"type": "string",
"description": "Name of branch to create PR in.",
},
},
"required": ["plan", "title", "summary", "branch"]
}
)
create_pr_function_call = {"name": "create_pr"}
def break_json(raw_json: str):
# turns something like {"function_call": {"arguments": " \""}}{"function_call": {"arguments": "summary"}} into two objects
try:
yield json.loads(raw_json)


I'm a bot that handles simple bugs and feature requests but I might make mistakes. Please be kind!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
sweep Assigns Sweep to an issue or pull request.
Projects
None yet
1 participant