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

Add command documentation #1171

Merged
merged 2 commits into from
Apr 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 83 additions & 31 deletions agixt/extensions/README.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,87 @@
## AGiXT Extensions
# AGiXT Extensions

Extensions are the way to extend the functionality of AGiXT with other software APIs or Python modules. Extensions are Python files that are placed in the `extensions` folder. AGiXT will automatically load all extensions and commands associated when it starts.

### Creating an Extension
## Creating an Extension

To create an extension, create a new Python file in the `extensions` folder. The file name will be the name of the extension. We will use the `GitHub` extension as an example.
To create an extension, create a new Python file in the `extensions` folder. The file name will be the name of the extension. We will make a smaller version of our `GitHub` extension as an example.

The example `GitHub` extension will have two commands:

The `GitHub` extension will have two commands:
- `Clone GitHub Repository`
- `Create GitHub Repository`

The `GibHub` extension will require two keys:

- `GITHUB_USERNAME` - The username of the GitHub account to use
- `GITHUB_API_KEY` - The API key of the GitHub account to use

All extensions will inherit from the `Extensions` class. This class will provide the following:

- `self.commands` - A dictionary of commands that the extension provides. The key is the name of the command and the value is the function that will be called when the command is run.
- `WORKING_DIRECTORY` - The directory that AGiXT Agent is allowed to work in.
- Any API Keys for your extension. In this case, `GITHUB_USERNAME` and `GITHUB_API_KEY`. Add these to `__init__` as shown below.
- Any imports that are required for your extension. In this case, `os`, `git`, and `Github`. Add try/excepts to install the modules if they are not already installed.
- Any imports that are required for your extension that are not built into Python. In this case, `GitPython`, and `PyGithub`. Add try/excepts to install the modules if they are not already installed.

```python
import os
import time
import datetime
from Extensions import Extensions

try:
import git
except ImportError:
import sys
import subprocess

subprocess.check_call([sys.executable, "-m", "pip", "install", "GitPython==3.1.31"])
subprocess.check_call([sys.executable, "-m", "pip", "install", "GitPython"])
import git

try:
from github import Github
from github import Github, RateLimitExceededException
except ImportError:
import sys
import subprocess

subprocess.check_call([sys.executable, "-m", "pip", "install", "PyGithub==1.58.2"])
from github import Github
from Extensions import Extensions
subprocess.check_call([sys.executable, "-m", "pip", "install", "PyGithub"])
from github import Github, RateLimitExceededException


class github(Extensions):
def __init__(
self,
GITHUB_USERNAME: str = "",
GITHUB_API_KEY: str = "",
WORKING_DIRECTORY: str = "./WORKSPACE",
**kwargs,
):
self.GITHUB_USERNAME = GITHUB_USERNAME
self.GITHUB_API_KEY = GITHUB_API_KEY
self.WORKING_DIRECTORY = WORKING_DIRECTORY
self.commands = {"Clone Github Repository": self.clone_repo}
if self.GITHUB_USERNAME and self.GITHUB_API_KEY:
self.commands["Create Github Repository"] = self.create_repo
self.commands = {
"Clone Github Repository": self.clone_repo,
"Create Github Repository": self.create_repo,
}
try:
self.gh = Github(self.GITHUB_API_KEY)
except Exception as e:
self.gh = None
self.commands = {}
print(f"GitHub Error: {str(e)}")
else:
self.commands = {}
self.gh = None
self.failures = 0

async def clone_repo(self, repo_url: str) -> str:
"""
Clone a GitHub repository to the local workspace

Args:
repo_url (str): The URL of the GitHub repository to clone

Returns:
str: The result of the cloning operation
"""
split_url = repo_url.split("//")
if self.GITHUB_USERNAME is not None and self.GITHUB_API_KEY is not None:
auth_repo_url = f"//{self.GITHUB_USERNAME}:{self.GITHUB_API_KEY}@".join(
Expand All @@ -68,29 +91,58 @@ class github(Extensions):
auth_repo_url = "//".join(split_url)
try:
repo_name = repo_url.split("/")[-1]
repo_dir = os.path.join(self.WORKING_DIRECTORY, repo_name)
repo_dir = os.path.join("./WORKSPACE", repo_name)
if os.path.exists(repo_dir):
return f"""{repo_dir} already exists"""
# Pull the latest changes
repo = git.Repo(repo_dir)
repo.remotes.origin.pull()
self.failures = 0
return f"Pulled latest changes for {repo_url} to {repo_dir}"
git.Repo.clone_from(
url=auth_repo_url,
to_path=repo_dir,
)
self.failures = 0
return f"Cloned {repo_url} to {repo_dir}"
except Exception as e:
if self.failures < 3:
self.failures += 1
time.sleep(5)
return await self.clone_repo(repo_url)
return f"Error: {str(e)}"

async def create_repo(self, repo_name: str, content_of_readme: str) -> str:
g = Github(self.GITHUB_API_KEY)
user = g.get_user(self.GITHUB_USERNAME)
repo = user.create_repo(repo_name, private=True)
repo_url = repo.clone_url
repo_dir = f"./{repo_name}"
repo = git.Repo.init(repo_dir)
with open(f"{repo_dir}/README.md", "w") as f:
f.write(content_of_readme)
repo.git.add(A=True)
repo.git.commit(m="Added README")
repo.create_remote("origin", repo_url)
repo.git.push("origin", "HEAD:main")
return repo_url
```
"""
Create a new private GitHub repository

Args:
repo_name (str): The name of the repository to create
content_of_readme (str): The content of the README.md file

Returns:
str: The URL of the newly created repository
"""
try:
try:
user = self.gh.get_organization(self.GITHUB_USERNAME)
except:
user = self.gh.get_user(self.GITHUB_USERNAME)
repo = user.create_repo(repo_name, private=True)
repo_url = repo.clone_url
repo_dir = f"./{repo_name}"
repo = git.Repo.init(repo_dir)
with open(f"{repo_dir}/README.md", "w") as f:
f.write(content_of_readme)
repo.git.add(A=True)
repo.git.commit(m="Added README")
repo.create_remote("origin", repo_url)
repo.git.push("origin", "HEAD:main")
self.failures = 0
return repo_url
except Exception as e:
if self.failures < 3:
self.failures += 1
time.sleep(5)
return await self.create_repo(repo_name, content_of_readme)
return f"Error: {str(e)}"
```
Loading
Loading