2023-09-16 17:53:28 +00:00
|
|
|
"""
|
|
|
|
This is a minimal file intended to be run by users to help them manage the autogpt projects.
|
|
|
|
|
2023-09-22 22:49:29 +00:00
|
|
|
If you want to contribute, please use only libraries that come as part of Python.
|
2023-09-16 17:53:28 +00:00
|
|
|
To ensure efficiency, add the imports to the functions so only what is needed is imported.
|
|
|
|
"""
|
2023-09-15 13:14:06 +00:00
|
|
|
try:
|
|
|
|
import click
|
|
|
|
except ImportError:
|
|
|
|
import os
|
2023-09-16 16:28:26 +00:00
|
|
|
|
|
|
|
os.system("pip3 install click")
|
2023-09-15 13:14:06 +00:00
|
|
|
import click
|
|
|
|
|
|
|
|
|
|
|
|
@click.group()
|
|
|
|
def cli():
|
|
|
|
pass
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
@cli.command()
|
|
|
|
def setup():
|
2023-09-15 13:44:11 +00:00
|
|
|
"""Installs dependencies needed for your system. Works with Linux, MacOS and Windows WSL."""
|
2023-09-15 13:14:06 +00:00
|
|
|
import os
|
|
|
|
import subprocess
|
2023-09-16 16:28:26 +00:00
|
|
|
|
2023-09-16 17:53:28 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
"""
|
|
|
|
d8888 888 .d8888b. 8888888b. 88888888888
|
|
|
|
d88888 888 d88P Y88b 888 Y88b 888
|
|
|
|
d88P888 888 888 888 888 888 888
|
|
|
|
d88P 888 888 888 888888 .d88b. 888 888 d88P 888
|
|
|
|
d88P 888 888 888 888 d88""88b 888 88888 8888888P" 888
|
|
|
|
d88P 888 888 888 888 888 888 888 888 888 888
|
|
|
|
d8888888888 Y88b 888 Y88b. Y88..88P Y88b d88P 888 888
|
|
|
|
d88P 888 "Y88888 "Y888 "Y88P" "Y8888P88 888 888
|
|
|
|
|
|
|
|
""",
|
|
|
|
fg="green",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
2023-09-16 16:28:26 +00:00
|
|
|
setup_script = os.path.join(script_dir, "setup.sh")
|
2023-09-17 16:41:06 +00:00
|
|
|
install_error = False
|
2023-09-15 13:14:06 +00:00
|
|
|
if os.path.exists(setup_script):
|
2023-09-16 17:53:28 +00:00
|
|
|
click.echo(click.style("🚀 Setup initiated...\n", fg="green"))
|
2023-09-17 16:41:06 +00:00
|
|
|
try:
|
|
|
|
subprocess.check_call([setup_script], cwd=script_dir)
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
click.echo(
|
|
|
|
click.style("❌ There was an issue with the installation.", fg="red")
|
|
|
|
)
|
|
|
|
install_error = True
|
2023-09-15 13:14:06 +00:00
|
|
|
else:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
"❌ Error: setup.sh does not exist in the current directory.", fg="red"
|
|
|
|
)
|
|
|
|
)
|
2023-09-17 16:41:06 +00:00
|
|
|
install_error = True
|
2023-09-15 17:44:37 +00:00
|
|
|
|
2023-09-17 16:41:06 +00:00
|
|
|
if install_error:
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
2023-09-22 22:49:29 +00:00
|
|
|
"\n\n🔴 If you need help, please raise a ticket on GitHub at https://github.com/Significant-Gravitas/AutoGPT/issues\n\n",
|
2023-09-17 16:41:06 +00:00
|
|
|
fg="magenta",
|
|
|
|
bold=True,
|
|
|
|
)
|
|
|
|
)
|
2023-09-15 17:44:37 +00:00
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
|
|
|
|
@cli.group()
|
2023-09-15 17:50:25 +00:00
|
|
|
def agent():
|
2023-09-15 13:44:11 +00:00
|
|
|
"""Commands to create, start and stop agents"""
|
2023-09-15 13:14:06 +00:00
|
|
|
pass
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
|
2023-09-15 17:50:25 +00:00
|
|
|
@agent.command()
|
2023-09-16 16:28:26 +00:00
|
|
|
@click.argument("agent_name")
|
2024-05-11 06:41:52 +00:00
|
|
|
def create(agent_name: str):
|
2023-10-19 10:05:20 +00:00
|
|
|
"""Create's a new agent with the agent name provided"""
|
2023-09-15 13:14:06 +00:00
|
|
|
import os
|
|
|
|
import re
|
2023-09-16 16:28:26 +00:00
|
|
|
import shutil
|
|
|
|
|
2023-11-16 09:23:25 +00:00
|
|
|
if not re.match(r"\w*$", agent_name):
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"😞 Agent name '{agent_name}' is not valid. It should not contain spaces or special characters other than -_",
|
|
|
|
fg="red",
|
|
|
|
)
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
return
|
|
|
|
try:
|
2024-05-22 12:08:54 +00:00
|
|
|
new_agent_dir = f"./agents/{agent_name}"
|
2023-10-30 14:36:14 +00:00
|
|
|
new_agent_name = f"{agent_name.lower()}.json"
|
2023-09-16 16:28:26 +00:00
|
|
|
|
2024-05-10 10:53:57 +00:00
|
|
|
if not os.path.exists(new_agent_dir):
|
2024-05-22 12:08:54 +00:00
|
|
|
shutil.copytree("./forge", new_agent_dir)
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
2024-05-22 12:08:54 +00:00
|
|
|
f"🎉 New agent '{agent_name}' created. The code for your new agent is in: agents/{agent_name}",
|
2023-09-16 16:28:26 +00:00
|
|
|
fg="green",
|
|
|
|
)
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
else:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
2023-10-30 14:36:14 +00:00
|
|
|
f"😞 Agent '{agent_name}' already exists. Enter a different name for your agent, the name needs to be unique regardless of case",
|
2023-09-16 16:28:26 +00:00
|
|
|
fg="red",
|
|
|
|
)
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
except Exception as e:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style(f"😢 An error occurred: {e}", fg="red"))
|
2023-09-15 13:14:06 +00:00
|
|
|
|
|
|
|
|
2023-09-15 17:50:25 +00:00
|
|
|
@agent.command()
|
2023-09-16 16:28:26 +00:00
|
|
|
@click.argument("agent_name")
|
2023-11-24 14:49:03 +00:00
|
|
|
@click.option(
|
|
|
|
"--no-setup",
|
|
|
|
is_flag=True,
|
|
|
|
help="Disables running the setup script before starting the agent",
|
|
|
|
)
|
2024-05-11 06:41:52 +00:00
|
|
|
def start(agent_name: str, no_setup: bool):
|
2023-09-15 13:14:06 +00:00
|
|
|
"""Start agent command"""
|
|
|
|
import os
|
|
|
|
import subprocess
|
2023-09-16 16:28:26 +00:00
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
2024-05-22 16:18:00 +00:00
|
|
|
agent_dir = os.path.join(
|
|
|
|
script_dir,
|
Set up unified pre-commit + CI w/ linting + type checking & FIX EVERYTHING (#7171)
- **FIX ALL LINT/TYPE ERRORS IN AUTOGPT, FORGE, AND BENCHMARK**
### Linting
- Clean up linter configs for `autogpt`, `forge`, and `benchmark`
- Add type checking with Pyright
- Create unified pre-commit config
- Create unified linting and type checking CI workflow
### Testing
- Synchronize CI test setups for `autogpt`, `forge`, and `benchmark`
- Add missing pytest-cov to benchmark dependencies
- Mark GCS tests as slow to speed up pre-commit test runs
- Repair `forge` test suite
- Add `AgentDB.close()` method for test DB teardown in db_test.py
- Use actual temporary dir instead of forge/test_workspace/
- Move left-behind dependencies for moved `forge`-code to from autogpt to forge
### Notable type changes
- Replace uses of `ChatModelProvider` by `MultiProvider`
- Removed unnecessary exports from various __init__.py
- Simplify `FileStorage.open_file` signature by removing `IOBase` from return type union
- Implement `S3BinaryIOWrapper(BinaryIO)` type interposer for `S3FileStorage`
- Expand overloads of `GCSFileStorage.open_file` for improved typing of read and write modes
Had to silence type checking for the extra overloads, because (I think) Pyright is reporting a false-positive:
https://github.com/microsoft/pyright/issues/8007
- Change `count_tokens`, `get_tokenizer`, `count_message_tokens` methods on `ModelProvider`s from class methods to instance methods
- Move `CompletionModelFunction.schema` method -> helper function `format_function_def_for_openai` in `forge.llm.providers.openai`
- Rename `ModelProvider` -> `BaseModelProvider`
- Rename `ChatModelProvider` -> `BaseChatModelProvider`
- Add type `ChatModelProvider` which is a union of all subclasses of `BaseChatModelProvider`
### Removed rather than fixed
- Remove deprecated and broken autogpt/agbenchmark_config/benchmarks.py
- Various base classes and properties on base classes in `forge.llm.providers.schema` and `forge.models.providers`
### Fixes for other issues that came to light
- Clean up `forge.agent_protocol.api_router`, `forge.agent_protocol.database`, and `forge.agent.agent`
- Add fallback behavior to `ImageGeneratorComponent`
- Remove test for deprecated failure behavior
- Fix `agbenchmark.challenges.builtin` challenge exclusion mechanism on Windows
- Fix `_tool_calls_compat_extract_calls` in `forge.llm.providers.openai`
- Add support for `any` (= no type specified) in `JSONSchema.typescript_type`
2024-05-28 03:04:21 +00:00
|
|
|
f"agents/{agent_name}"
|
|
|
|
if agent_name not in ["autogpt", "forge"]
|
|
|
|
else agent_name,
|
2024-05-22 16:18:00 +00:00
|
|
|
)
|
2023-09-16 16:28:26 +00:00
|
|
|
run_command = os.path.join(agent_dir, "run")
|
2023-09-28 16:38:55 +00:00
|
|
|
run_bench_command = os.path.join(agent_dir, "run_benchmark")
|
2024-03-22 12:25:23 +00:00
|
|
|
if (
|
|
|
|
os.path.exists(agent_dir)
|
2024-05-11 06:45:51 +00:00
|
|
|
and os.path.isfile(run_command)
|
2024-03-22 12:25:23 +00:00
|
|
|
and os.path.isfile(run_bench_command)
|
|
|
|
):
|
2023-09-15 13:14:06 +00:00
|
|
|
os.chdir(agent_dir)
|
2023-10-08 18:39:38 +00:00
|
|
|
if not no_setup:
|
2024-02-15 10:26:26 +00:00
|
|
|
click.echo(f"⌛ Running setup for agent '{agent_name}'...")
|
2023-10-05 17:13:59 +00:00
|
|
|
setup_process = subprocess.Popen(["./setup"], cwd=agent_dir)
|
|
|
|
setup_process.wait()
|
2024-02-15 10:26:26 +00:00
|
|
|
click.echo()
|
|
|
|
|
2023-09-28 16:38:55 +00:00
|
|
|
subprocess.Popen(["./run_benchmark", "serve"], cwd=agent_dir)
|
2024-02-15 10:26:26 +00:00
|
|
|
click.echo("⌛ (Re)starting benchmark server...")
|
|
|
|
wait_until_conn_ready(8080)
|
|
|
|
click.echo()
|
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
subprocess.Popen(["./run"], cwd=agent_dir)
|
2024-02-15 10:26:26 +00:00
|
|
|
click.echo(f"⌛ (Re)starting agent '{agent_name}'...")
|
|
|
|
wait_until_conn_ready(8000)
|
|
|
|
click.echo("✅ Agent application started and available on port 8000")
|
2023-09-15 13:14:06 +00:00
|
|
|
elif not os.path.exists(agent_dir):
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"😞 Agent '{agent_name}' does not exist. Please create the agent first.",
|
|
|
|
fg="red",
|
|
|
|
)
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
else:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"😞 Run command does not exist in the agent '{agent_name}' directory.",
|
|
|
|
fg="red",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
|
2023-09-15 17:50:25 +00:00
|
|
|
@agent.command()
|
2023-09-15 13:14:06 +00:00
|
|
|
def stop():
|
|
|
|
"""Stop agent command"""
|
|
|
|
import os
|
|
|
|
import signal
|
2023-09-16 16:28:26 +00:00
|
|
|
import subprocess
|
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
try:
|
2023-10-09 15:32:52 +00:00
|
|
|
pids = subprocess.check_output(["lsof", "-t", "-i", ":8000"]).split()
|
|
|
|
if isinstance(pids, int):
|
|
|
|
os.kill(int(pids), signal.SIGTERM)
|
|
|
|
else:
|
|
|
|
for pid in pids:
|
|
|
|
os.kill(int(pid), signal.SIGTERM)
|
2023-09-29 09:03:52 +00:00
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
click.echo("No process is running on port 8000")
|
2023-09-15 13:14:06 +00:00
|
|
|
|
2023-09-29 09:03:52 +00:00
|
|
|
try:
|
2023-10-09 15:32:52 +00:00
|
|
|
pids = int(subprocess.check_output(["lsof", "-t", "-i", ":8080"]))
|
|
|
|
if isinstance(pids, int):
|
|
|
|
os.kill(int(pids), signal.SIGTERM)
|
|
|
|
else:
|
|
|
|
for pid in pids:
|
|
|
|
os.kill(int(pid), signal.SIGTERM)
|
2023-09-29 09:03:52 +00:00
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
click.echo("No process is running on port 8080")
|
2023-09-15 13:14:06 +00:00
|
|
|
|
2024-03-22 12:25:23 +00:00
|
|
|
|
2023-09-15 17:50:25 +00:00
|
|
|
@agent.command()
|
2023-09-15 13:14:06 +00:00
|
|
|
def list():
|
|
|
|
"""List agents command"""
|
|
|
|
import os
|
2023-09-16 16:28:26 +00:00
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
try:
|
2024-05-22 12:08:54 +00:00
|
|
|
agents_dir = "./agents"
|
2023-09-16 16:28:26 +00:00
|
|
|
agents_list = [
|
|
|
|
d
|
|
|
|
for d in os.listdir(agents_dir)
|
|
|
|
if os.path.isdir(os.path.join(agents_dir, d))
|
|
|
|
]
|
2024-05-22 16:18:00 +00:00
|
|
|
if os.path.isdir("./autogpt"):
|
|
|
|
agents_list.append("autogpt")
|
2023-09-15 13:14:06 +00:00
|
|
|
if agents_list:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style("Available agents: 🤖", fg="green"))
|
2023-09-15 13:14:06 +00:00
|
|
|
for agent in agents_list:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style(f"\t🐙 {agent}", fg="blue"))
|
2023-09-15 13:14:06 +00:00
|
|
|
else:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style("No agents found 😞", fg="red"))
|
2023-09-15 13:14:06 +00:00
|
|
|
except FileNotFoundError:
|
2024-05-22 12:08:54 +00:00
|
|
|
click.echo(click.style("The agents directory does not exist 😢", fg="red"))
|
2023-09-15 13:14:06 +00:00
|
|
|
except Exception as e:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style(f"An error occurred: {e} 😢", fg="red"))
|
2023-09-15 13:14:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
@cli.group()
|
|
|
|
def benchmark():
|
2023-09-15 13:44:11 +00:00
|
|
|
"""Commands to start the benchmark and list tests and categories"""
|
2023-09-15 13:14:06 +00:00
|
|
|
pass
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
|
|
|
|
@benchmark.command(
|
|
|
|
context_settings=dict(
|
|
|
|
ignore_unknown_options=True,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
@click.argument("agent_name")
|
|
|
|
@click.argument("subprocess_args", nargs=-1, type=click.UNPROCESSED)
|
2023-09-15 13:14:06 +00:00
|
|
|
def start(agent_name, subprocess_args):
|
|
|
|
"""Starts the benchmark command"""
|
|
|
|
import os
|
|
|
|
import subprocess
|
2023-09-16 16:28:26 +00:00
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
2024-05-22 16:18:00 +00:00
|
|
|
agent_dir = os.path.join(
|
|
|
|
script_dir,
|
Set up unified pre-commit + CI w/ linting + type checking & FIX EVERYTHING (#7171)
- **FIX ALL LINT/TYPE ERRORS IN AUTOGPT, FORGE, AND BENCHMARK**
### Linting
- Clean up linter configs for `autogpt`, `forge`, and `benchmark`
- Add type checking with Pyright
- Create unified pre-commit config
- Create unified linting and type checking CI workflow
### Testing
- Synchronize CI test setups for `autogpt`, `forge`, and `benchmark`
- Add missing pytest-cov to benchmark dependencies
- Mark GCS tests as slow to speed up pre-commit test runs
- Repair `forge` test suite
- Add `AgentDB.close()` method for test DB teardown in db_test.py
- Use actual temporary dir instead of forge/test_workspace/
- Move left-behind dependencies for moved `forge`-code to from autogpt to forge
### Notable type changes
- Replace uses of `ChatModelProvider` by `MultiProvider`
- Removed unnecessary exports from various __init__.py
- Simplify `FileStorage.open_file` signature by removing `IOBase` from return type union
- Implement `S3BinaryIOWrapper(BinaryIO)` type interposer for `S3FileStorage`
- Expand overloads of `GCSFileStorage.open_file` for improved typing of read and write modes
Had to silence type checking for the extra overloads, because (I think) Pyright is reporting a false-positive:
https://github.com/microsoft/pyright/issues/8007
- Change `count_tokens`, `get_tokenizer`, `count_message_tokens` methods on `ModelProvider`s from class methods to instance methods
- Move `CompletionModelFunction.schema` method -> helper function `format_function_def_for_openai` in `forge.llm.providers.openai`
- Rename `ModelProvider` -> `BaseModelProvider`
- Rename `ChatModelProvider` -> `BaseChatModelProvider`
- Add type `ChatModelProvider` which is a union of all subclasses of `BaseChatModelProvider`
### Removed rather than fixed
- Remove deprecated and broken autogpt/agbenchmark_config/benchmarks.py
- Various base classes and properties on base classes in `forge.llm.providers.schema` and `forge.models.providers`
### Fixes for other issues that came to light
- Clean up `forge.agent_protocol.api_router`, `forge.agent_protocol.database`, and `forge.agent.agent`
- Add fallback behavior to `ImageGeneratorComponent`
- Remove test for deprecated failure behavior
- Fix `agbenchmark.challenges.builtin` challenge exclusion mechanism on Windows
- Fix `_tool_calls_compat_extract_calls` in `forge.llm.providers.openai`
- Add support for `any` (= no type specified) in `JSONSchema.typescript_type`
2024-05-28 03:04:21 +00:00
|
|
|
f"agents/{agent_name}"
|
|
|
|
if agent_name not in ["autogpt", "forge"]
|
|
|
|
else agent_name,
|
2024-05-22 16:18:00 +00:00
|
|
|
)
|
2023-09-18 15:56:23 +00:00
|
|
|
benchmark_script = os.path.join(agent_dir, "run_benchmark")
|
2023-09-15 13:14:06 +00:00
|
|
|
if os.path.exists(agent_dir) and os.path.isfile(benchmark_script):
|
|
|
|
os.chdir(agent_dir)
|
|
|
|
subprocess.Popen([benchmark_script, *subprocess_args], cwd=agent_dir)
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"🚀 Running benchmark for '{agent_name}' with subprocess arguments: {' '.join(subprocess_args)}",
|
|
|
|
fg="green",
|
|
|
|
)
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
else:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"😞 Agent '{agent_name}' does not exist. Please create the agent first.",
|
|
|
|
fg="red",
|
|
|
|
)
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
@benchmark.group(name="categories")
|
2023-09-15 13:14:06 +00:00
|
|
|
def benchmark_categories():
|
|
|
|
"""Benchmark categories group command"""
|
|
|
|
pass
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
|
|
|
|
@benchmark_categories.command(name="list")
|
2023-09-15 13:14:06 +00:00
|
|
|
def benchmark_categories_list():
|
|
|
|
"""List benchmark categories command"""
|
|
|
|
import glob
|
2023-09-16 16:28:26 +00:00
|
|
|
import json
|
|
|
|
import os
|
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
categories = set()
|
|
|
|
|
|
|
|
# Get the directory of this file
|
|
|
|
this_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
glob_path = os.path.join(
|
|
|
|
this_dir, "./benchmark/agbenchmark/challenges/**/[!deprecated]*/data.json"
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
# Use it as the base for the glob pattern, excluding 'deprecated' directory
|
|
|
|
for data_file in glob.glob(glob_path, recursive=True):
|
2024-03-22 12:25:23 +00:00
|
|
|
if "deprecated" not in data_file:
|
2023-09-18 15:56:23 +00:00
|
|
|
with open(data_file, "r") as f:
|
|
|
|
try:
|
|
|
|
data = json.load(f)
|
|
|
|
categories.update(data.get("category", []))
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
print(f"Error: {data_file} is not a valid JSON file.")
|
|
|
|
continue
|
|
|
|
except IOError:
|
|
|
|
print(f"IOError: file could not be read: {data_file}")
|
|
|
|
continue
|
2023-09-15 13:14:06 +00:00
|
|
|
|
|
|
|
if categories:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style("Available categories: 📚", fg="green"))
|
2023-09-15 13:14:06 +00:00
|
|
|
for category in categories:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style(f"\t📖 {category}", fg="blue"))
|
2023-09-15 13:14:06 +00:00
|
|
|
else:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style("No categories found 😞", fg="red"))
|
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
@benchmark.group(name="tests")
|
2023-09-15 13:14:06 +00:00
|
|
|
def benchmark_tests():
|
|
|
|
"""Benchmark tests group command"""
|
|
|
|
pass
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
|
|
|
|
@benchmark_tests.command(name="list")
|
2023-09-15 13:14:06 +00:00
|
|
|
def benchmark_tests_list():
|
|
|
|
"""List benchmark tests command"""
|
|
|
|
import glob
|
2023-09-16 16:28:26 +00:00
|
|
|
import json
|
|
|
|
import os
|
2023-09-15 13:14:06 +00:00
|
|
|
import re
|
2023-09-16 16:28:26 +00:00
|
|
|
|
2023-09-15 13:14:06 +00:00
|
|
|
tests = {}
|
|
|
|
|
|
|
|
# Get the directory of this file
|
|
|
|
this_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
glob_path = os.path.join(
|
|
|
|
this_dir, "./benchmark/agbenchmark/challenges/**/[!deprecated]*/data.json"
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
# Use it as the base for the glob pattern, excluding 'deprecated' directory
|
|
|
|
for data_file in glob.glob(glob_path, recursive=True):
|
2024-03-22 12:25:23 +00:00
|
|
|
if "deprecated" not in data_file:
|
2023-09-18 15:56:23 +00:00
|
|
|
with open(data_file, "r") as f:
|
|
|
|
try:
|
|
|
|
data = json.load(f)
|
|
|
|
category = data.get("category", [])
|
|
|
|
test_name = data.get("name", "")
|
|
|
|
if category and test_name:
|
|
|
|
if category[0] not in tests:
|
|
|
|
tests[category[0]] = []
|
|
|
|
tests[category[0]].append(test_name)
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
print(f"Error: {data_file} is not a valid JSON file.")
|
|
|
|
continue
|
|
|
|
except IOError:
|
|
|
|
print(f"IOError: file could not be read: {data_file}")
|
|
|
|
continue
|
2023-09-15 13:14:06 +00:00
|
|
|
|
|
|
|
if tests:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style("Available tests: 📚", fg="green"))
|
2023-09-15 13:14:06 +00:00
|
|
|
for category, test_list in tests.items():
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style(f"\t📖 {category}", fg="blue"))
|
2023-09-15 13:14:06 +00:00
|
|
|
for test in sorted(test_list):
|
2023-09-16 16:28:26 +00:00
|
|
|
test_name = (
|
|
|
|
" ".join(word for word in re.split("([A-Z][a-z]*)", test) if word)
|
|
|
|
.replace("_", "")
|
2023-09-18 14:40:30 +00:00
|
|
|
.replace("C L I", "CLI")
|
2023-09-16 16:28:26 +00:00
|
|
|
.replace(" ", " ")
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
test_name_padded = f"{test_name:<40}"
|
2023-09-18 15:56:23 +00:00
|
|
|
click.echo(click.style(f"\t\t🔬 {test_name_padded} - {test}", fg="cyan"))
|
2023-09-15 13:14:06 +00:00
|
|
|
else:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(click.style("No tests found 😞", fg="red"))
|
|
|
|
|
|
|
|
|
|
|
|
@benchmark_tests.command(name="details")
|
|
|
|
@click.argument("test_name")
|
2023-09-15 13:14:06 +00:00
|
|
|
def benchmark_tests_details(test_name):
|
|
|
|
"""Benchmark test details command"""
|
|
|
|
import glob
|
2023-09-16 16:28:26 +00:00
|
|
|
import json
|
|
|
|
import os
|
2023-09-15 13:14:06 +00:00
|
|
|
|
|
|
|
# Get the directory of this file
|
|
|
|
this_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
glob_path = os.path.join(
|
|
|
|
this_dir, "./benchmark/agbenchmark/challenges/**/[!deprecated]*/data.json"
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
# Use it as the base for the glob pattern, excluding 'deprecated' directory
|
|
|
|
for data_file in glob.glob(glob_path, recursive=True):
|
|
|
|
with open(data_file, "r") as f:
|
|
|
|
try:
|
|
|
|
data = json.load(f)
|
|
|
|
if data.get("name") == test_name:
|
2023-09-16 16:28:26 +00:00
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\n{data.get('name')}\n{'-'*len(data.get('name'))}\n",
|
|
|
|
fg="blue",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\tCategory: {', '.join(data.get('category'))}",
|
|
|
|
fg="green",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(click.style(f"\tTask: {data.get('task')}", fg="green"))
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\tDependencies: {', '.join(data.get('dependencies')) if data.get('dependencies') else 'None'}",
|
|
|
|
fg="green",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style(f"\tCutoff: {data.get('cutoff')}\n", fg="green")
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style("\tTest Conditions\n\t-------", fg="magenta")
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\t\tAnswer: {data.get('ground').get('answer')}",
|
|
|
|
fg="magenta",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\t\tShould Contain: {', '.join(data.get('ground').get('should_contain'))}",
|
|
|
|
fg="magenta",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\t\tShould Not Contain: {', '.join(data.get('ground').get('should_not_contain'))}",
|
|
|
|
fg="magenta",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\t\tFiles: {', '.join(data.get('ground').get('files'))}",
|
|
|
|
fg="magenta",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\t\tEval: {data.get('ground').get('eval').get('type')}\n",
|
|
|
|
fg="magenta",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(click.style("\tInfo\n\t-------", fg="yellow"))
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\t\tDifficulty: {data.get('info').get('difficulty')}",
|
|
|
|
fg="yellow",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\t\tDescription: {data.get('info').get('description')}",
|
|
|
|
fg="yellow",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
click.echo(
|
|
|
|
click.style(
|
|
|
|
f"\t\tSide Effects: {', '.join(data.get('info').get('side_effects'))}",
|
|
|
|
fg="yellow",
|
|
|
|
)
|
|
|
|
)
|
2023-09-15 13:14:06 +00:00
|
|
|
break
|
|
|
|
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
print(f"Error: {data_file} is not a valid JSON file.")
|
|
|
|
continue
|
|
|
|
except IOError:
|
|
|
|
print(f"IOError: file could not be read: {data_file}")
|
|
|
|
continue
|
2023-09-16 16:28:26 +00:00
|
|
|
|
2024-03-22 12:25:23 +00:00
|
|
|
|
|
|
|
def wait_until_conn_ready(port: int = 8000, timeout: int = 30):
|
|
|
|
"""
|
|
|
|
Polls localhost:{port} until it is available for connections
|
|
|
|
|
|
|
|
Params:
|
|
|
|
port: The port for which to wait until it opens
|
|
|
|
timeout: Timeout in seconds; maximum amount of time to wait
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
TimeoutError: If the timeout (seconds) expires before the port opens
|
|
|
|
"""
|
2024-02-15 10:26:26 +00:00
|
|
|
import socket
|
2024-03-22 12:25:23 +00:00
|
|
|
import time
|
2024-02-15 10:26:26 +00:00
|
|
|
|
2024-03-22 12:25:23 +00:00
|
|
|
start = time.time()
|
2024-02-15 10:26:26 +00:00
|
|
|
while True:
|
|
|
|
time.sleep(0.5)
|
|
|
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
2024-03-22 12:25:23 +00:00
|
|
|
if s.connect_ex(("localhost", port)) == 0:
|
2024-02-15 10:26:26 +00:00
|
|
|
break
|
2024-03-22 12:25:23 +00:00
|
|
|
if time.time() > start + timeout:
|
|
|
|
raise TimeoutError(f"Port {port} did not open within {timeout} seconds")
|
2024-02-15 10:26:26 +00:00
|
|
|
|
|
|
|
|
2023-09-16 16:28:26 +00:00
|
|
|
if __name__ == "__main__":
|
2023-09-15 13:14:06 +00:00
|
|
|
cli()
|