--debug for CLI commands (#454)
``` (base) ➜ arcade-ai git:(debug) ✗ uv run arcade busted-command --host invalid-host ❌ Login failed with error: Not implemented ^C Aborted. (base) ➜ arcade-ai git:(debug) ✗ uv run arcade busted-command --host invalid-host --debug ❌ Login failed with error: Traceback (most recent call last): File "/Users/evan/workspace/arcade/Team/arcade-ai/libs/arcade-cli/arcade_cli/main.py", line 106, in login raise Exception("Not implemented") Exception: Not implemented ```
This commit is contained in:
parent
836c890840
commit
6889d8673b
1 changed files with 65 additions and 42 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import asyncio
|
||||
import os
|
||||
import threading
|
||||
import traceback
|
||||
import uuid
|
||||
import webbrowser
|
||||
from pathlib import Path
|
||||
|
|
@ -69,6 +70,21 @@ cli.add_typer(
|
|||
console = Console()
|
||||
|
||||
|
||||
def handle_cli_error(
|
||||
message: str, error: Exception | None = None, debug: bool = True, should_exit: bool = True
|
||||
) -> None:
|
||||
"""Handle CLI error reporting with optional debug traceback and exit."""
|
||||
if error and debug:
|
||||
console.print(f"❌ {message}: {traceback.format_exc()}", style="bold red")
|
||||
elif error:
|
||||
console.print(f"❌ {message}: {escape(str(error))}", style="bold red")
|
||||
else:
|
||||
console.print(f"❌ {message}", style="bold red")
|
||||
|
||||
if should_exit:
|
||||
raise typer.Exit(code=1)
|
||||
|
||||
|
||||
@cli.command(help="Log in to Arcade Cloud", rich_help_panel="User")
|
||||
def login(
|
||||
host: str = typer.Option(
|
||||
|
|
@ -83,6 +99,7 @@ def login(
|
|||
"--port",
|
||||
help="The port of the Arcade Cloud host (if running locally).",
|
||||
),
|
||||
debug: bool = typer.Option(False, "--debug", "-d", help="Show debug information"),
|
||||
) -> None:
|
||||
"""
|
||||
Logs the user into Arcade Cloud.
|
||||
|
|
@ -115,22 +132,29 @@ def login(
|
|||
server_thread.join()
|
||||
except KeyboardInterrupt:
|
||||
auth_server.shutdown_server()
|
||||
except Exception as e:
|
||||
handle_cli_error("Login failed", e, debug)
|
||||
finally:
|
||||
if server_thread.is_alive():
|
||||
server_thread.join() # Ensure the server thread completes and cleans up
|
||||
|
||||
|
||||
@cli.command(help="Log out of Arcade Cloud", rich_help_panel="User")
|
||||
def logout() -> None:
|
||||
def logout(
|
||||
debug: bool = typer.Option(False, "--debug", "-d", help="Show debug information"),
|
||||
) -> None:
|
||||
"""
|
||||
Logs the user out of Arcade Cloud.
|
||||
"""
|
||||
# If the credentials file exists, delete it
|
||||
if os.path.exists(CREDENTIALS_FILE_PATH):
|
||||
os.remove(CREDENTIALS_FILE_PATH)
|
||||
console.print("You're now logged out.", style="bold")
|
||||
else:
|
||||
console.print("You're not logged in.", style="bold red")
|
||||
try:
|
||||
# If the credentials file exists, delete it
|
||||
if os.path.exists(CREDENTIALS_FILE_PATH):
|
||||
os.remove(CREDENTIALS_FILE_PATH)
|
||||
console.print("You're now logged out.", style="bold")
|
||||
else:
|
||||
console.print("You're not logged in.", style="bold red")
|
||||
except Exception as e:
|
||||
handle_cli_error("Logout failed", e, debug)
|
||||
|
||||
|
||||
@cli.command(
|
||||
|
|
@ -143,6 +167,7 @@ def new(
|
|||
metavar="TOOLKIT_NAME",
|
||||
),
|
||||
directory: str = typer.Option(os.getcwd(), "--dir", help="tools directory path"),
|
||||
debug: bool = typer.Option(False, "--debug", "-d", help="Show debug information"),
|
||||
) -> None:
|
||||
"""
|
||||
Creates a new toolkit with the given name, description, and result type.
|
||||
|
|
@ -152,8 +177,7 @@ def new(
|
|||
try:
|
||||
create_new_toolkit(directory, toolkit_name)
|
||||
except Exception as e:
|
||||
error_message = f"❌ Failed to create new Toolkit: {escape(str(e))}"
|
||||
console.print(error_message, style="bold red")
|
||||
handle_cli_error("Failed to create new Toolkit", e, debug)
|
||||
|
||||
|
||||
@cli.command(
|
||||
|
|
@ -318,7 +342,7 @@ def chat(
|
|||
tool_messages = chat_result.tool_messages
|
||||
|
||||
except OpenAIError as e:
|
||||
console.print(f"❌ Arcade Chat failed with error: {e!s}", style="bold red")
|
||||
handle_cli_error("Arcade Chat failed", e, debug, should_exit=False)
|
||||
continue
|
||||
if debug:
|
||||
display_tool_messages(tool_messages)
|
||||
|
|
@ -328,9 +352,7 @@ def chat(
|
|||
typer.Exit()
|
||||
|
||||
except RuntimeError as e:
|
||||
error_message = f"❌ Failed to run tool{': ' + escape(str(e)) if str(e) else ''}"
|
||||
console.print(error_message, style="bold red")
|
||||
raise typer.Exit()
|
||||
handle_cli_error("Failed to run tool", e, debug)
|
||||
|
||||
|
||||
@cli.command(help="Run tool calling evaluations", rich_help_panel="Tool Development")
|
||||
|
|
@ -376,6 +398,7 @@ def evals(
|
|||
"--no-tls",
|
||||
help="Whether to disable TLS for the connection to the Arcade Engine.",
|
||||
),
|
||||
debug: bool = typer.Option(False, "--debug", help="Show debug information"),
|
||||
) -> None:
|
||||
"""
|
||||
Find all files starting with 'eval_' in the given directory,
|
||||
|
|
@ -463,7 +486,10 @@ def evals(
|
|||
all_evaluations.extend(results)
|
||||
display_eval_results(all_evaluations, show_details=show_details)
|
||||
|
||||
asyncio.run(run_evaluations())
|
||||
try:
|
||||
asyncio.run(run_evaluations())
|
||||
except Exception as e:
|
||||
handle_cli_error("Failed to run evaluations", e, debug)
|
||||
|
||||
|
||||
@cli.command(
|
||||
|
|
@ -523,9 +549,7 @@ def serve(
|
|||
except KeyboardInterrupt:
|
||||
typer.Exit()
|
||||
except Exception as e:
|
||||
error_message = f"❌ Failed to start Arcade Worker: {escape(str(e))}"
|
||||
console.print(error_message, style="bold red")
|
||||
typer.Exit(code=1)
|
||||
handle_cli_error("Failed to start Arcade Worker", e, debug)
|
||||
|
||||
|
||||
@cli.command(
|
||||
|
|
@ -574,9 +598,7 @@ def workerup(
|
|||
except KeyboardInterrupt:
|
||||
typer.Exit()
|
||||
except Exception as e:
|
||||
error_message = f"❌ Failed to start Arcade Toolkit Server: {escape(str(e))}"
|
||||
console.print(error_message, style="bold red")
|
||||
typer.Exit(code=1)
|
||||
handle_cli_error("Failed to start Arcade Toolkit Server", e, debug)
|
||||
|
||||
|
||||
@cli.command(help="Deploy toolkits to Arcade Cloud", rich_help_panel="Deployment")
|
||||
|
|
@ -620,6 +642,7 @@ def deploy(
|
|||
"--no-tls",
|
||||
help="Whether to disable TLS for the connection to the Arcade Engine.",
|
||||
),
|
||||
debug: bool = typer.Option(False, "--debug", help="Show debug information"),
|
||||
) -> None:
|
||||
"""
|
||||
Deploy a worker to Arcade Cloud.
|
||||
|
|
@ -637,8 +660,7 @@ def deploy(
|
|||
try:
|
||||
deployment = Deployment.from_toml(Path(deployment_file))
|
||||
except Exception as e:
|
||||
console.print(f"❌ Failed to parse deployment file: {e}", style="bold red")
|
||||
raise typer.Exit(code=1)
|
||||
handle_cli_error("Failed to parse deployment file", e, debug)
|
||||
|
||||
with console.status(f"Deploying {len(deployment.worker)} workers"):
|
||||
for worker in deployment.worker:
|
||||
|
|
@ -648,10 +670,7 @@ def deploy(
|
|||
worker.request().execute(cloud_client, engine_client)
|
||||
console.log(f"✅ Worker '{worker.config.id}' deployed successfully.", style="dim")
|
||||
except Exception as e:
|
||||
console.log(
|
||||
f"❌ Failed to deploy worker '{worker.config.id}': {e}", style="bold red"
|
||||
)
|
||||
raise typer.Exit(code=1)
|
||||
handle_cli_error(f"Failed to deploy worker '{worker.config.id}'", e, debug)
|
||||
|
||||
|
||||
@cli.command(help="Open the Arcade Dashboard in a web browser", rich_help_panel="User")
|
||||
|
|
@ -684,30 +703,34 @@ def dashboard(
|
|||
"--no-tls",
|
||||
help="Whether to disable TLS for the connection to the Arcade Engine.",
|
||||
),
|
||||
debug: bool = typer.Option(False, "--debug", "-d", help="Show debug information"),
|
||||
) -> None:
|
||||
"""Opens the Arcade Dashboard in a web browser.
|
||||
|
||||
The Dashboard is a web-based Arcade user interface that is served by the Arcade Engine.
|
||||
"""
|
||||
if local:
|
||||
host = "localhost"
|
||||
try:
|
||||
if local:
|
||||
host = "localhost"
|
||||
|
||||
# Construct base URL (for both health check and dashboard)
|
||||
base_url = compute_base_url(force_tls, force_no_tls, host, port)
|
||||
dashboard_url = f"{base_url}/dashboard"
|
||||
# Construct base URL (for both health check and dashboard)
|
||||
base_url = compute_base_url(force_tls, force_no_tls, host, port)
|
||||
dashboard_url = f"{base_url}/dashboard"
|
||||
|
||||
# Try to hit /health endpoint on engine and warn if it is down
|
||||
config = validate_and_get_config()
|
||||
with Arcade(api_key=config.api.key, base_url=base_url) as client:
|
||||
log_engine_health(client)
|
||||
# Try to hit /health endpoint on engine and warn if it is down
|
||||
config = validate_and_get_config()
|
||||
with Arcade(api_key=config.api.key, base_url=base_url) as client:
|
||||
log_engine_health(client)
|
||||
|
||||
# Open the dashboard in a browser
|
||||
console.print(f"Opening Arcade Dashboard at {dashboard_url}")
|
||||
if not webbrowser.open(dashboard_url):
|
||||
console.print(
|
||||
f"If a browser doesn't open automatically, copy this URL and paste it into your browser: {dashboard_url}",
|
||||
style="dim",
|
||||
)
|
||||
# Open the dashboard in a browser
|
||||
console.print(f"Opening Arcade Dashboard at {dashboard_url}")
|
||||
if not webbrowser.open(dashboard_url):
|
||||
console.print(
|
||||
f"If a browser doesn't open automatically, copy this URL and paste it into your browser: {dashboard_url}",
|
||||
style="dim",
|
||||
)
|
||||
except Exception as e:
|
||||
handle_cli_error("Failed to open dashboard", e, debug)
|
||||
|
||||
|
||||
@cli.callback()
|
||||
|
|
|
|||
Loading…
Reference in a new issue