diff --git a/README.md b/README.md index b2b58bb8..d12b02ee 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ agentstack tools add ## Running Your Agent -`python src/main.py` +`agentstack run` Runs the agent project in development mode.
diff --git a/agentstack/cli/cli.py b/agentstack/cli/cli.py index 7277db32..902d0de3 100644 --- a/agentstack/cli/cli.py +++ b/agentstack/cli/cli.py @@ -311,7 +311,7 @@ def insert_template(project_details: dict, framework_name: str, design: dict): " Next, run:\n" f" cd {project_metadata.project_slug}\n" " poetry install\n" - " poetry run python src/main.py\n\n" + " agentstack run\n\n" " Add agents and tasks with:\n" " `agentstack generate agent/task `\n\n" " Run `agentstack quickstart` or `agentstack docs` for next steps.\n" diff --git a/agentstack/main.py b/agentstack/main.py index fdc61804..e72871c6 100644 --- a/agentstack/main.py +++ b/agentstack/main.py @@ -1,8 +1,10 @@ import argparse +import os import sys from agentstack.cli import init_project_builder, list_tools -from agentstack.utils import get_version +from agentstack.telemetry import track_cli_command +from agentstack.utils import get_version, get_framework import agentstack.generation as generation import webbrowser @@ -28,6 +30,9 @@ def main(): init_parser.add_argument('slug_name', nargs='?', help="The directory name to place the project in") init_parser.add_argument('--no-wizard', action='store_true', help="Skip wizard steps") + # 'run' command + run_parser = subparsers.add_parser('run', aliases=['r'], help='Run your agent') + # 'generate' command generate_parser = subparsers.add_parser('generate', aliases=['g'], help='Generate agents or tasks') @@ -74,6 +79,8 @@ def main(): print(f"AgentStack CLI version: {get_version()}") return + track_cli_command(args.command) + # Handle commands if args.command in ['docs']: webbrowser.open('https://docs.agentstack.sh/') @@ -81,6 +88,10 @@ def main(): webbrowser.open('https://docs.agentstack.sh/quickstart') if args.command in ['init', 'i']: init_project_builder(args.slug_name, args.no_wizard) + if args.command in ['run', 'r']: + framework = get_framework() + if framework == "crewai": + os.system('python src/main.py') elif args.command in ['generate', 'g']: if args.generate_command in ['agent', 'a']: generation.generate_agent(args.name, args.role, args.goal, args.backstory, args.llm) diff --git a/agentstack/telemetry.py b/agentstack/telemetry.py new file mode 100644 index 00000000..0a43d610 --- /dev/null +++ b/agentstack/telemetry.py @@ -0,0 +1,73 @@ +# hi :) +# +# if you're reading this, you probably saw "telemetry.py" and +# got mad and went to go see how we're spying on you +# +# i really hate to put this functionality in and was very +# resistant to it. as a human, i value privacy as a fundamental +# human right. but i also value my time. +# +# i have been putting a lot of my time into building out +# agentstack. i have strong conviction for what this project +# can be. it's showing some great progress, but for me to justify +# spending days and nights building this, i need to know that +# people are actually using it and not just starring the repo +# +# if you want to opt-out of telemetry, you can add the following +# configuration to your agentstack.json file: +# +# telemetry_opt_out: false +# +# i'm a single developer with a passion, working to lower the barrier +# of entry to building and deploying agents. it would be really +# cool of you to allow telemetry <3 +# +# - braelyn + +import platform +import socket +import psutil +import requests +from agentstack.utils import get_telemetry_opt_out, get_framework, get_version + +# TELEMETRY_URL = 'https://api.agentstack.sh/telemetry' +TELEMETRY_URL = 'http://localhost:3000/telemetry' + +def collect_machine_telemetry(): + if get_telemetry_opt_out(): + return + + telemetry_data = { + 'os': platform.system(), + 'hostname': socket.gethostname(), + 'platform': platform.platform(), + 'os_version': platform.version(), + 'cpu_count': psutil.cpu_count(logical=True), + 'memory': psutil.virtual_memory().total, + 'framework': get_framework(), + 'agentstack_version': get_version() + } + + # Attempt to get general location based on public IP + try: + response = requests.get('https://ipinfo.io/json') + if response.status_code == 200: + location_data = response.json() + telemetry_data.update({ + 'ip': location_data.get('ip'), + 'city': location_data.get('city'), + 'region': location_data.get('region'), + 'country': location_data.get('country') + }) + except requests.RequestException as e: + telemetry_data['location_error'] = str(e) + + return telemetry_data + + +def track_cli_command(command): + try: + data = collect_machine_telemetry() + requests.post(TELEMETRY_URL, json={"command": command, **data}) + except: + pass diff --git a/agentstack/utils.py b/agentstack/utils.py index 822208d5..29fe8d5d 100644 --- a/agentstack/utils.py +++ b/agentstack/utils.py @@ -41,6 +41,19 @@ def get_framework(path: Optional[str] = None) -> str: sys.exit(1) +def get_telemetry_opt_out(path: Optional[str] = None) -> str: + try: + file_path = 'agentstack.json' + if path is not None: + file_path = path + '/' + file_path + + agentstack_data = open_json_file(file_path) + opt_out = agentstack_data.get('telemetry_opt_out', False) + return opt_out + except FileNotFoundError: + print("\033[31mFile agentstack.json does not exist. Are you in the right directory?\033[0m") + sys.exit(1) + def camel_to_snake(name): s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() diff --git a/pyproject.toml b/pyproject.toml index cf628a70..03fb6ffb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "agentstack" -version = "0.1.9" +version = "0.1.10" description = "The fastest way to build robust AI agents" authors = [ { name="Braelyn Boynton", email="bboynton97@gmail.com" }