Skip to content

Commit

Permalink
Merge branch 'main' into fancy-init
Browse files Browse the repository at this point in the history
# Conflicts:
#	agentstack/main.py
#	agentstack/templates/crewai/{{cookiecutter.project_metadata.project_slug}}/pyproject.toml
  • Loading branch information
bboynton97 committed Jan 9, 2025
2 parents 609b1bb + 6bcbe71 commit c840a8f
Show file tree
Hide file tree
Showing 67 changed files with 8,650 additions and 311 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Codecov

on:
push:
branches:
- main
paths:
- 'agentstack/**/*.py'
pull_request:
branches:
- main
paths:
- 'agentstack/**/*.py'

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.11

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox
- name: Run tests with tox
run: tox

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: true
38 changes: 38 additions & 0 deletions .github/workflows/mintlify-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Mintlify Documentation Check
on:
pull_request:
paths:
- 'docs/**' # Only trigger on changes to docs directory
- 'mint.json' # Also trigger on mintlify config changes

jobs:
build-docs:
name: Build Documentation
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'

- name: Install Mintlify
run: npm install -g mintlify

- name: Test documentation
run: |
cd docs
# If mintlify dev has errors, it will exit with status 1
# If it starts successfully, kill it after 5 seconds
timeout 5s mintlify dev || exit_status=$?
if [ $exit_status -eq 124 ]; then
# timeout exit code 124 means the process was killed after starting successfully
echo "Documentation built successfully!"
exit 0
else
echo "Documentation failed to build! Try running `mintlify dev` from the docs dir locally"
exit 1
fi
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,14 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

# aider
.aider*

# VSCode
.vscode

# AgentStack
.agentstack*
example_project/
ex/
**/ex/
Expand All @@ -171,5 +178,6 @@ cookiecutter.json
examples/tests/
examples/tests/**/*

uv.lock
.DS_Store

59 changes: 41 additions & 18 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ First of all, __thank you__ for your interest in contributing to AgentStack! Eve

Our vision is to build the defacto CLI for quickly spinning up an AI Agent project. We want to be the [create-react-app](https://create-react-app.dev/) of agents. Our inspiration also includes the oh-so-convenient [Angular CLI](https://v17.angular.io/cli).

### Exclusive Contributor Sticker
AgentStack contributors all receive a free sticker pack including an exclusive holographic sticker only available to contributors to the project :)

Once your PR is merge, fill out [this form](https://docs.google.com/forms/d/e/1FAIpQLSfvBEnsT8nsQleonJHoWQtHuhbsgUJ0a9IjOqeZbMGkga2NtA/viewform?usp=sf_link) and I'll send your sticker pack out ASAP! <3

## How to Help

Grab an issue from the [issues tab](https://github.com/AgentOps-AI/AgentStack/issues)! Plenty are labelled "Good First Issue". Fork the repo and create a PR when ready!
Expand All @@ -12,28 +17,17 @@ The best place to engage in conversation about your contribution is in the Issue
## Setup

1. Clone the repo
2. `poetry install`
3. `pip install -e .[dev,test]`
- This will install the CLI locally and in editable mode so you can use `agentstack <command>` to test your latest changes
`git clone https://github.com/AgentOps-AI/AgentStack.git`
`cd AgentStack`
2. Install agentstack as an edtiable project and set it up for development and testing
`pip install -e .[dev,test]`
This will install the CLI locally and in editable mode so you can use `agentstack <command>` to test your latest changes

## Project Structure
TODO

## Adding Tools
If you're reading this section, you probably have a product that AI agents can use as a tool. We're glad you're here!

Adding tools is easy once you understand the project structure. A few things need to be done for a tool to be considered completely supported:

1. Modify `agentstack/tools/tools.json`
- Add your tool and relevant information to this file as appropriate.
2. Create a config for your tool
- As an example, look at `mem0.json`
- AgentStack uses this to know what code to insert where. Follow the structure to add your tool.
3. Create your implementation for each framework
- In `agentstack/templates/<framework>/tools`, you'll see other implementations of tools.
- Build your tool implementation for that framework. This file will be inserted in the user's project.
- The tools that are exported from this file should be listed in the tool's config json.
4. Manually test your tool integration by running `agentstack tools add <your_tool>` and ensure it behaves as expected.
Adding tools is easy once you understand the project structure. Our documentation for adding tools is available on our hosted docs [here](https://docs.agentstack.sh/contributing/adding-tools).

## Before creating your PR
Be sure that you are opening a PR using a branch other than `main` on your fork. This enables us
Expand All @@ -59,4 +53,33 @@ pre-commit install
```

## Tests
HAHAHAHAHAHAHA good one
CLI tests are a bit hacky, so we are not tracking coverage.
That said, _some_ testing is required for any new functionality added by a PR.

Tests MUST pass to have your PR merged. We _will not_ allow main to be in a failing state, so if your tests are failing, this is your problem to fix.

### Run tests locally
Install the testing requirements
```bash
pip install 'agentstack[test]'
```

Then run tests in all supported python versions with
```bash
tox
```

## Need Help?
If you're reading this, we're very thankful you wanted to contribute! I understand it can be a little overwhelming to
get up to speed on a project like this and we are here to help!

### Open a draft PR
While we can't promise to write code for you, if you're stuck or need advice/help, open a draft PR and explain what you were trying to build and where you're stuck! Chances are, one of us have the context needed to help you get unstuck :)

### Chat on our Discord
We have an active [Discord server](https://discord.gg/JdWkh9tgTQ) with contributors and AgentStack users! There is a channel just for contributors on there. Feel free to drop a message explaining what you're trying to build and why you're stuck. Someone from our team should reply soon!

# Thank You!
The team behind AgentStack believe that the barrier to entry for building agents is far too high right now! We believe that this technology can be streamlined and made more accessible. If you're here, you likely feel the same! Any contribution is appreciated.

If you're looking for work, we are _always_ open to hiring passionate engineers of all skill levels! While closing issues cannot guarantee an offer, we've found that engineers who contribute to our open source repo are some of the best we could ever hope to find via recruiters! Be active in the community and let us know you're interested in joining the team!
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# AgentStack [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/release/python-3100/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
# AgentStack [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/release/python-3100/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![python-testing](https://github.com/agentops-ai/agentstack/actions/workflows/python-testing.yml/badge.svg) ![mypy](https://github.com/agentops-ai/agentstack/actions/workflows/mypy.yml/badge.svg) [![codecov.io](https://codecov.io/github/agentops-ai/agentstack/coverage.svg?branch=master)](https://codecov.io/github/agentops-ai/agentstack>?branch=master)

<img alt="Logo" align="right" src="https://raw.githubusercontent.com/bboynton97/agentstack-docs/3491fe490ea535e7def74c83182dfa8dcfb1f562/logo/dark-sm.svg" width="20%" />

Expand Down
142 changes: 142 additions & 0 deletions agentstack/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import parse_qs, urlparse
import webbrowser
import json
import os
import threading
import socket
from pathlib import Path

import inquirer
from appdirs import user_data_dir
from agentstack.logger import log


try:
base_dir = Path(user_data_dir("agentstack", "agency"))
# Test if we can write to directory
test_file = base_dir / '.test_write_permission'
test_file.touch()
test_file.unlink()
except (RuntimeError, OSError, PermissionError):
# In CI or when directory is not writable, use temp directory
base_dir = Path(os.getenv('TEMP', '/tmp'))


class AuthCallbackHandler(BaseHTTPRequestHandler):
def do_GET(self):
"""Handle the OAuth callback from the browser"""
try:
# Parse the query parameters
query_components = parse_qs(urlparse(self.path).query)

# Extract the token from query parameters
token = query_components.get('token', [''])[0]

if token:
# Store the token
base_dir.mkdir(exist_ok=True, parents=True)

with open(base_dir / 'auth.json', 'w') as f:
json.dump({'bearer_token': token}, f)

# Send success response
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()

success_html = """
<html>
<body>
<script>
setTimeout(function() {
window.close();
}, 1000);
</script>
<h2>Authentication successful! You can close this window.</h2>
</body>
</html>
"""
self.wfile.write(success_html.encode())

# Signal the main thread that we're done
self.server.authentication_successful = True
else:
self.send_response(400)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(b'Authentication failed: No token received')

except Exception as e:
self.send_response(500)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(f'Error: {str(e)}'.encode())

def find_free_port():
"""Find a free port on localhost"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 0))
s.listen(1)
port = s.getsockname()[1]
return port

def start_auth_server():
"""Start the local authentication server"""
port = find_free_port()
server = HTTPServer(('localhost', port), AuthCallbackHandler)
server.authentication_successful = False
return server, port


def login():
"""Log in to AgentStack"""
try:
# check if already logged in
token = get_stored_token()
if token:
print("You are already authenticated!")
if not inquirer.confirm('Would you like to log in with a different account?'):
return

# Start the local server
server, port = start_auth_server()

# Create server thread
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()

# Open the browser to the login page
auth_url_base = os.getenv('AGENTSTACK_AUTHORIZATION_BASE_URL', 'https://agentstack.sh')
auth_url = f"{auth_url_base}/login?callback_port={port}"
webbrowser.open(auth_url)

# Wait for authentication to complete
while not server.authentication_successful:
pass

# Cleanup
server.shutdown()
server_thread.join()

print("🔐 Authentication successful! Token has been stored.")
return True

except Exception as e:
log.warn(f"Authentication failed: {str(e)}", err=True)
return False


def get_stored_token():
"""Retrieve the stored bearer token"""
try:
auth_path = base_dir / 'auth.json'
if not auth_path.exists():
return None

with open(auth_path) as f:
config = json.load(f)
return config.get('bearer_token')
except Exception:
return None
10 changes: 9 additions & 1 deletion agentstack/cli/agentstack_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,16 @@ def to_json(self):


class ProjectStructure:
def __init__(self):
def __init__(
self,
method: str = "sequential",
manager_agent: Optional[str] = None,
):
self.agents = []
self.tasks = []
self.inputs = {}
self.method = method
self.manager_agent = manager_agent

def add_agent(self, agent):
self.agents.append(agent)
Expand All @@ -67,6 +73,8 @@ def set_inputs(self, inputs):

def to_dict(self):
return {
'method': self.method,
'manager_agent': self.manager_agent,
'agents': self.agents,
'tasks': self.tasks,
'inputs': self.inputs,
Expand Down
Loading

0 comments on commit c840a8f

Please sign in to comment.