732 lines
24 KiB
Python
732 lines
24 KiB
Python
# Copyright (c) 2025 ByteDance Ltd. and/or its affiliates
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""Command Line Interface for Trae Agent."""
|
|
|
|
import asyncio
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import traceback
|
|
from pathlib import Path
|
|
|
|
import click
|
|
from dotenv import load_dotenv
|
|
from rich.console import Console
|
|
from rich.panel import Panel
|
|
from rich.table import Table
|
|
from rich.text import Text
|
|
|
|
from trae_agent.agent import Agent
|
|
from trae_agent.utils.cli import CLIConsole, ConsoleFactory, ConsoleMode, ConsoleType
|
|
from trae_agent.utils.config import Config, TraeAgentConfig
|
|
|
|
# Load environment variables
|
|
_ = load_dotenv()
|
|
|
|
console = Console()
|
|
|
|
|
|
def resolve_config_file(config_file: str) -> str:
|
|
"""
|
|
Resolve config file with backward compatibility.
|
|
First tries the specified file, then falls back to JSON if YAML doesn't exist.
|
|
"""
|
|
if config_file.endswith(".yaml") or config_file.endswith(".yml"):
|
|
yaml_path = Path(config_file)
|
|
json_path = Path(config_file.replace(".yaml", ".json").replace(".yml", ".json"))
|
|
if yaml_path.exists():
|
|
return str(yaml_path)
|
|
elif json_path.exists():
|
|
console.print(f"[yellow]YAML config not found, using JSON config: {json_path}[/yellow]")
|
|
return str(json_path)
|
|
else:
|
|
console.print(
|
|
"[red]Error: Config file not found. Please specify a valid config file in the command line option --config-file[/red]"
|
|
)
|
|
sys.exit(1)
|
|
else:
|
|
return config_file
|
|
|
|
|
|
def check_docker(timeout=3):
|
|
# 1) Check whether the docker CLI is installed
|
|
if shutil.which("docker") is None:
|
|
return {
|
|
"cli": False,
|
|
"daemon": False,
|
|
"version": None,
|
|
"error": "docker CLI not found",
|
|
}
|
|
# 2) Check whether the Docker daemon is reachable (this makes a real request)
|
|
try:
|
|
cp = subprocess.run(
|
|
["docker", "version", "--format", "{{.Server.Version}}"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=timeout,
|
|
)
|
|
if cp.returncode == 0 and cp.stdout.strip():
|
|
return {
|
|
"cli": True,
|
|
"daemon": True,
|
|
"version": cp.stdout.strip(),
|
|
"error": None,
|
|
}
|
|
else:
|
|
# The daemon may not be running or permissions may be insufficient
|
|
return {
|
|
"cli": True,
|
|
"daemon": False,
|
|
"version": None,
|
|
"error": (cp.stderr or cp.stdout).strip(),
|
|
}
|
|
except Exception as e:
|
|
return {"cli": True, "daemon": False, "version": None, "error": str(e)}
|
|
|
|
|
|
def build_with_pyinstaller():
|
|
os.system("rm -rf trae_agent/dist")
|
|
print("--- Building edit_tool ---")
|
|
subprocess.run(
|
|
[
|
|
"pyinstaller",
|
|
"--name",
|
|
"edit_tool",
|
|
"trae_agent/tools/edit_tool_cli.py",
|
|
],
|
|
check=True,
|
|
)
|
|
print("\n--- Building json_edit_tool ---")
|
|
subprocess.run(
|
|
[
|
|
"pyinstaller",
|
|
"--name",
|
|
"json_edit_tool",
|
|
"--hidden-import=jsonpath_ng",
|
|
"trae_agent/tools/json_edit_tool_cli.py",
|
|
],
|
|
check=True,
|
|
)
|
|
os.system("mkdir trae_agent/dist")
|
|
os.system("cp dist/edit_tool/edit_tool trae_agent/dist")
|
|
os.system("cp -r dist/json_edit_tool/_internal trae_agent/dist")
|
|
os.system("cp dist/json_edit_tool/json_edit_tool trae_agent/dist")
|
|
os.system("rm -rf dist")
|
|
|
|
|
|
@click.group()
|
|
@click.version_option(version="0.1.0")
|
|
def cli():
|
|
"""Trae Agent - LLM-based agent for software engineering tasks."""
|
|
pass
|
|
|
|
|
|
@cli.command()
|
|
@click.argument("task", required=False)
|
|
@click.option("--file", "-f", "file_path", help="Path to a file containing the task description.")
|
|
@click.option("--provider", "-p", help="LLM provider to use")
|
|
@click.option("--model", "-m", help="Specific model to use")
|
|
@click.option("--model-base-url", help="Base URL for the model API")
|
|
@click.option("--api-key", "-k", help="API key (or set via environment variable)")
|
|
@click.option("--max-steps", help="Maximum number of execution steps", type=int)
|
|
@click.option("--working-dir", "-w", help="Working directory for the agent")
|
|
@click.option("--must-patch", "-mp", is_flag=True, help="Whether to patch the code")
|
|
@click.option(
|
|
"--config-file",
|
|
help="Path to configuration file",
|
|
default="trae_config.yaml",
|
|
envvar="TRAE_CONFIG_FILE",
|
|
)
|
|
@click.option("--trajectory-file", "-t", help="Path to save trajectory file")
|
|
@click.option("--patch-path", "-pp", help="Path to patch file")
|
|
# --- Docker Mode Start ---
|
|
@click.option(
|
|
"--docker-image",
|
|
type=str,
|
|
default=None,
|
|
help="Specify a Docker image to run the task in a new container",
|
|
)
|
|
@click.option(
|
|
"--docker-container-id",
|
|
type=str,
|
|
default=None,
|
|
help="Attach to an existing Docker container by ID",
|
|
)
|
|
@click.option(
|
|
"--dockerfile-path",
|
|
type=click.Path(exists=True, dir_okay=False, resolve_path=True),
|
|
default=None,
|
|
help="Absolute path to a Dockerfile to build an environment",
|
|
)
|
|
@click.option(
|
|
"--docker-image-file",
|
|
type=click.Path(exists=True, dir_okay=False, resolve_path=True),
|
|
default=None,
|
|
help="Path to a local Docker image file (tar archive) to load.",
|
|
)
|
|
@click.option(
|
|
"--docker-keep",
|
|
type=bool,
|
|
default=True,
|
|
help="Keep or remove the Docker container after finishing the task",
|
|
)
|
|
# --- Docker Mode End ---
|
|
|
|
|
|
@click.option(
|
|
"--console-type",
|
|
"-ct",
|
|
default="simple",
|
|
type=click.Choice(["simple", "rich"], case_sensitive=False),
|
|
help="Type of console to use (simple or rich)",
|
|
)
|
|
@click.option(
|
|
"--agent-type",
|
|
"-at",
|
|
type=click.Choice(["trae_agent"], case_sensitive=False),
|
|
help="Type of agent to use (trae_agent)",
|
|
default="trae_agent",
|
|
)
|
|
def run(
|
|
task: str | None,
|
|
file_path: str | None,
|
|
patch_path: str,
|
|
provider: str | None = None,
|
|
model: str | None = None,
|
|
model_base_url: str | None = None,
|
|
api_key: str | None = None,
|
|
max_steps: int | None = None,
|
|
working_dir: str | None = None,
|
|
must_patch: bool = False,
|
|
config_file: str = "trae_config.yaml",
|
|
trajectory_file: str | None = None,
|
|
console_type: str | None = "simple",
|
|
agent_type: str | None = "trae_agent",
|
|
# --- Add Docker Mode ---
|
|
docker_image: str | None = None,
|
|
docker_container_id: str | None = None,
|
|
dockerfile_path: str | None = None,
|
|
docker_image_file: str | None = None,
|
|
docker_keep: bool = True,
|
|
):
|
|
"""
|
|
Run is the main function of trae. it runs a task using Trae Agent.
|
|
Args:
|
|
tasks: the task that you want your agent to solve. This is required to be in the input
|
|
model: the model expected to be use
|
|
working_dir: the working directory of the agent. This should be set either in cli or in the config file
|
|
|
|
Return:
|
|
None (it is expected to be ended after calling the run function)
|
|
"""
|
|
|
|
docker_config: dict[str, str | None] | None = None
|
|
if (
|
|
sum(
|
|
[
|
|
bool(docker_image),
|
|
bool(docker_container_id),
|
|
bool(dockerfile_path),
|
|
bool(docker_image_file),
|
|
]
|
|
)
|
|
> 1
|
|
):
|
|
console.print(
|
|
"[red]Error: --docker-image, --docker-container-id, --dockerfile-path, and --docker-image-file are mutually exclusive.[/red]"
|
|
)
|
|
sys.exit(1)
|
|
|
|
if dockerfile_path:
|
|
docker_config = {"dockerfile_path": dockerfile_path}
|
|
console.print(
|
|
f"[blue]Docker mode enabled. Building from Dockerfile: {dockerfile_path}[/blue]"
|
|
)
|
|
elif docker_image_file:
|
|
docker_config = {"docker_image_file": docker_image_file}
|
|
console.print(
|
|
f"[blue]Docker mode enabled. Loading from image file: {docker_image_file}[/blue]"
|
|
)
|
|
elif docker_container_id:
|
|
docker_config = {"container_id": docker_container_id}
|
|
console.print(
|
|
f"[blue]Docker mode enabled. Attaching to container: {docker_container_id}[/blue]"
|
|
)
|
|
elif docker_image:
|
|
docker_config = {"image": docker_image}
|
|
console.print(f"[blue]Docker mode enabled. Using image: {docker_image}[/blue]")
|
|
# --- ADDED END ---
|
|
|
|
# Apply backward compatibility for config file
|
|
config_file = resolve_config_file(config_file)
|
|
|
|
if docker_config:
|
|
check_msg = check_docker()
|
|
if check_msg["cli"] and check_msg["daemon"] and check_msg["version"]:
|
|
print("Docker is configured correctly.")
|
|
else:
|
|
print(f"Docker is configured incorrectly. {check_msg['error']}")
|
|
sys.exit(1)
|
|
if not (os.path.exists("trae_agent/dist") and os.path.exists("trae_agent/dist/_internal")):
|
|
print("Building tools of Docker mode for the first use, waiting for a few seconds...")
|
|
build_with_pyinstaller()
|
|
print("Building finished.")
|
|
|
|
if file_path:
|
|
if task:
|
|
console.print(
|
|
"[red]Error: Cannot use both a task string and the --file argument.[/red]"
|
|
)
|
|
sys.exit(1)
|
|
try:
|
|
task = Path(file_path).read_text()
|
|
except FileNotFoundError:
|
|
console.print(f"[red]Error: File not found: {file_path}[/red]")
|
|
sys.exit(1)
|
|
elif not task:
|
|
console.print(
|
|
"[red]Error: Must provide either a task string or use the --file argument.[/red]"
|
|
)
|
|
sys.exit(1)
|
|
|
|
config = Config.create(
|
|
config_file=config_file,
|
|
).resolve_config_values(
|
|
provider=provider,
|
|
model=model,
|
|
model_base_url=model_base_url,
|
|
api_key=api_key,
|
|
max_steps=max_steps,
|
|
)
|
|
|
|
if not agent_type:
|
|
console.print("[red]Error: agent_type is required.[/red]")
|
|
sys.exit(1)
|
|
|
|
# Create CLI Console
|
|
console_mode = ConsoleMode.RUN
|
|
if console_type:
|
|
selected_console_type = (
|
|
ConsoleType.SIMPLE if console_type.lower() == "simple" else ConsoleType.RICH
|
|
)
|
|
else:
|
|
selected_console_type = ConsoleFactory.get_recommended_console_type(console_mode)
|
|
|
|
cli_console = ConsoleFactory.create_console(
|
|
console_type=selected_console_type, mode=console_mode
|
|
)
|
|
|
|
# For rich console in RUN mode, set the initial task
|
|
if selected_console_type == ConsoleType.RICH and hasattr(cli_console, "set_initial_task"):
|
|
cli_console.set_initial_task(task)
|
|
|
|
# agent = Agent(agent_type, config, trajectory_file, cli_console)
|
|
|
|
if docker_config is not None:
|
|
docker_config["workspace_dir"] = working_dir # now type-safe
|
|
|
|
# Change working directory if specified
|
|
if working_dir:
|
|
try:
|
|
Path(working_dir).mkdir(parents=True, exist_ok=True)
|
|
# os.chdir(working_dir)
|
|
console.print(f"[blue]Changed working directory to: {working_dir}[/blue]")
|
|
working_dir = os.path.abspath(working_dir)
|
|
except Exception as e:
|
|
error_text = Text(f"Error changing directory: {e}", style="red")
|
|
console.print(error_text)
|
|
sys.exit(1)
|
|
else:
|
|
working_dir = os.getcwd()
|
|
console.print(f"[blue]Using current directory as working directory: {working_dir}[/blue]")
|
|
|
|
# Ensure working directory is an absolute path
|
|
if not Path(working_dir).is_absolute():
|
|
console.print(
|
|
f"[red]Working directory must be an absolute path: {working_dir}, it should start with `/`[/red]"
|
|
)
|
|
sys.exit(1)
|
|
|
|
agent = Agent(
|
|
agent_type,
|
|
config,
|
|
trajectory_file,
|
|
cli_console,
|
|
docker_config=docker_config,
|
|
docker_keep=docker_keep,
|
|
)
|
|
|
|
if not docker_config:
|
|
try:
|
|
os.chdir(working_dir)
|
|
except Exception as e:
|
|
error_text = Text(f"Error changing directory: {e}", style="red")
|
|
console.print(error_text)
|
|
sys.exit(1)
|
|
|
|
try:
|
|
task_args = {
|
|
"project_path": working_dir,
|
|
"issue": task,
|
|
"must_patch": "true" if must_patch else "false",
|
|
"patch_path": patch_path,
|
|
}
|
|
|
|
# Set up agent context for rich console if applicable
|
|
if selected_console_type == ConsoleType.RICH and hasattr(cli_console, "set_agent_context"):
|
|
cli_console.set_agent_context(agent, config.trae_agent, config_file, trajectory_file)
|
|
|
|
# Agent will handle starting the appropriate console
|
|
_ = asyncio.run(agent.run(task, task_args))
|
|
|
|
console.print(f"\n[green]Trajectory saved to: {agent.trajectory_file}[/green]")
|
|
|
|
except KeyboardInterrupt:
|
|
console.print("\n[yellow]Task execution interrupted by user[/yellow]")
|
|
console.print(f"[blue]Partial trajectory saved to: {agent.trajectory_file}[/blue]")
|
|
sys.exit(1)
|
|
except Exception as e:
|
|
try:
|
|
from docker.errors import DockerException
|
|
|
|
if isinstance(e, DockerException):
|
|
error_text = Text(f"Docker Error: {e}", style="red")
|
|
console.print(f"\n{error_text}")
|
|
console.print(
|
|
"[yellow]Please ensure the Docker daemon is running and you have the necessary permissions.[/yellow]"
|
|
)
|
|
else:
|
|
raise e
|
|
except ImportError:
|
|
error_text = Text(f"Unexpected error: {e}", style="red")
|
|
console.print(f"\n{error_text}")
|
|
console.print(traceback.format_exc())
|
|
except Exception:
|
|
error_text = Text(f"Unexpected error: {e}", style="red")
|
|
console.print(f"\n{error_text}")
|
|
console.print(traceback.format_exc())
|
|
console.print(f"[blue]Trajectory saved to: {agent.trajectory_file}[/blue]")
|
|
sys.exit(1)
|
|
|
|
|
|
@cli.command()
|
|
@click.option("--provider", "-p", help="LLM provider to use")
|
|
@click.option("--model", "-m", help="Specific model to use")
|
|
@click.option("--model-base-url", help="Base URL for the model API")
|
|
@click.option("--api-key", "-k", help="API key (or set via environment variable)")
|
|
@click.option(
|
|
"--config-file",
|
|
help="Path to configuration file",
|
|
default="trae_config.yaml",
|
|
envvar="TRAE_CONFIG_FILE",
|
|
)
|
|
@click.option("--max-steps", help="Maximum number of execution steps", type=int, default=20)
|
|
@click.option("--trajectory-file", "-t", help="Path to save trajectory file")
|
|
@click.option(
|
|
"--console-type",
|
|
"-ct",
|
|
type=click.Choice(["simple", "rich"], case_sensitive=False),
|
|
help="Type of console to use (simple or rich)",
|
|
)
|
|
@click.option(
|
|
"--agent-type",
|
|
"-at",
|
|
type=click.Choice(["trae_agent"], case_sensitive=False),
|
|
help="Type of agent to use (trae_agent)",
|
|
default="trae_agent",
|
|
)
|
|
def interactive(
|
|
provider: str | None = None,
|
|
model: str | None = None,
|
|
model_base_url: str | None = None,
|
|
api_key: str | None = None,
|
|
config_file: str = "trae_config.yaml",
|
|
max_steps: int | None = None,
|
|
trajectory_file: str | None = None,
|
|
console_type: str | None = "simple",
|
|
agent_type: str | None = "trae_agent",
|
|
):
|
|
"""
|
|
This function starts an interactive session with Trae Agent.
|
|
Args:
|
|
console_type: Type of console to use for the interactive session
|
|
"""
|
|
# Apply backward compatibility for config file
|
|
config_file = resolve_config_file(config_file)
|
|
|
|
config = Config.create(
|
|
config_file=config_file,
|
|
).resolve_config_values(
|
|
provider=provider,
|
|
model=model,
|
|
model_base_url=model_base_url,
|
|
api_key=api_key,
|
|
max_steps=max_steps,
|
|
)
|
|
|
|
if config.trae_agent:
|
|
trae_agent_config = config.trae_agent
|
|
else:
|
|
console.print("[red]Error: trae_agent configuration is required in the config file.[/red]")
|
|
sys.exit(1)
|
|
|
|
# Create CLI Console for interactive mode
|
|
console_mode = ConsoleMode.INTERACTIVE
|
|
if console_type:
|
|
selected_console_type = (
|
|
ConsoleType.SIMPLE if console_type.lower() == "simple" else ConsoleType.RICH
|
|
)
|
|
else:
|
|
selected_console_type = ConsoleFactory.get_recommended_console_type(console_mode)
|
|
|
|
cli_console = ConsoleFactory.create_console(
|
|
console_type=selected_console_type,
|
|
lakeview_config=config.lakeview,
|
|
mode=console_mode,
|
|
)
|
|
|
|
if not agent_type:
|
|
console.print("[red]Error: agent_type is required.[/red]")
|
|
sys.exit(1)
|
|
|
|
# Create agent
|
|
agent = Agent(agent_type, config, trajectory_file, cli_console)
|
|
|
|
# Get the actual trajectory file path (in case it was auto-generated)
|
|
trajectory_file = agent.trajectory_file
|
|
|
|
# For simple console, use traditional interactive loop
|
|
if selected_console_type == ConsoleType.SIMPLE:
|
|
asyncio.run(
|
|
_run_simple_interactive_loop(
|
|
agent, cli_console, trae_agent_config, config_file, trajectory_file
|
|
)
|
|
)
|
|
else:
|
|
# For rich console, start the textual app which handles interaction
|
|
asyncio.run(
|
|
_run_rich_interactive_loop(
|
|
agent, cli_console, trae_agent_config, config_file, trajectory_file
|
|
)
|
|
)
|
|
|
|
|
|
async def _run_simple_interactive_loop(
|
|
agent: Agent,
|
|
cli_console: CLIConsole,
|
|
trae_agent_config: TraeAgentConfig,
|
|
config_file: str,
|
|
trajectory_file: str | None,
|
|
):
|
|
"""Run the interactive loop for simple console."""
|
|
while True:
|
|
try:
|
|
task = cli_console.get_task_input()
|
|
if task is None:
|
|
console.print("[green]Goodbye![/green]")
|
|
break
|
|
|
|
if task.lower() == "help":
|
|
console.print(
|
|
Panel(
|
|
"""[bold]Available Commands:[/bold]
|
|
|
|
• Type any task description to execute it
|
|
• 'status' - Show agent status
|
|
• 'clear' - Clear the screen
|
|
• 'exit' or 'quit' - End the session""",
|
|
title="Help",
|
|
border_style="yellow",
|
|
)
|
|
)
|
|
continue
|
|
|
|
working_dir = cli_console.get_working_dir_input()
|
|
|
|
if task.lower() == "status":
|
|
console.print(
|
|
Panel(
|
|
f"""[bold]Provider:[/bold] {agent.agent_config.model.model_provider.provider}
|
|
[bold]Model:[/bold] {agent.agent_config.model.model}
|
|
[bold]Available Tools:[/bold] {len(agent.agent.tools)}
|
|
[bold]Config File:[/bold] {config_file}
|
|
[bold]Working Directory:[/bold] {os.getcwd()}""",
|
|
title="Agent Status",
|
|
border_style="blue",
|
|
)
|
|
)
|
|
continue
|
|
|
|
if task.lower() == "clear":
|
|
console.clear()
|
|
continue
|
|
|
|
# Set up trajectory recording for this task
|
|
console.print(f"[blue]Trajectory will be saved to: {trajectory_file}[/blue]")
|
|
|
|
task_args = {
|
|
"project_path": working_dir,
|
|
"issue": task,
|
|
"must_patch": "false",
|
|
}
|
|
|
|
# Execute the task
|
|
console.print(f"\n[blue]Executing task: {task}[/blue]")
|
|
|
|
# Start console and execute task
|
|
console_task = asyncio.create_task(cli_console.start())
|
|
execution_task = asyncio.create_task(agent.run(task, task_args))
|
|
|
|
# Wait for execution to complete
|
|
_ = await execution_task
|
|
_ = await console_task
|
|
|
|
console.print(f"\n[green]Trajectory saved to: {trajectory_file}[/green]")
|
|
|
|
except KeyboardInterrupt:
|
|
console.print("\n[yellow]Use 'exit' or 'quit' to end the session[/yellow]")
|
|
except EOFError:
|
|
console.print("\n[green]Goodbye![/green]")
|
|
break
|
|
except Exception as e:
|
|
error_text = Text(f"Error: {e}", style="red")
|
|
console.print(error_text)
|
|
|
|
|
|
async def _run_rich_interactive_loop(
|
|
agent: Agent,
|
|
cli_console: CLIConsole,
|
|
trae_agent_config: TraeAgentConfig,
|
|
config_file: str,
|
|
trajectory_file: str | None,
|
|
):
|
|
"""Run the interactive loop for rich console."""
|
|
# Set up the agent in the rich console so it can handle task execution
|
|
if hasattr(cli_console, "set_agent_context"):
|
|
cli_console.set_agent_context(agent, trae_agent_config, config_file, trajectory_file)
|
|
|
|
# Start the console UI - this will handle the entire interaction
|
|
await cli_console.start()
|
|
|
|
|
|
@cli.command()
|
|
@click.option(
|
|
"--config-file",
|
|
help="Path to configuration file",
|
|
default="trae_config.yaml",
|
|
envvar="TRAE_CONFIG_FILE",
|
|
)
|
|
@click.option("--provider", "-p", help="LLM provider to use")
|
|
@click.option("--model", "-m", help="Specific model to use")
|
|
@click.option("--model-base-url", help="Base URL for the model API")
|
|
@click.option("--api-key", "-k", help="API key (or set via environment variable)")
|
|
@click.option("--max-steps", help="Maximum number of execution steps", type=int)
|
|
def show_config(
|
|
config_file: str,
|
|
provider: str | None,
|
|
model: str | None,
|
|
model_base_url: str | None,
|
|
api_key: str | None,
|
|
max_steps: int | None,
|
|
):
|
|
"""Show current configuration settings."""
|
|
# Apply backward compatibility for config file
|
|
config_file = resolve_config_file(config_file)
|
|
|
|
config_path = Path(config_file)
|
|
if not config_path.exists():
|
|
console.print(
|
|
Panel(
|
|
f"""[yellow]No configuration file found at: {config_file}[/yellow]
|
|
|
|
Using default settings and environment variables.""",
|
|
title="Configuration Status",
|
|
border_style="yellow",
|
|
)
|
|
)
|
|
|
|
config = Config.create(
|
|
config_file=config_file,
|
|
).resolve_config_values(
|
|
provider=provider,
|
|
model=model,
|
|
model_base_url=model_base_url,
|
|
api_key=api_key,
|
|
max_steps=max_steps,
|
|
)
|
|
|
|
if config.trae_agent:
|
|
trae_agent_config = config.trae_agent
|
|
else:
|
|
console.print("[red]Error: trae_agent configuration is required in the config file.[/red]")
|
|
sys.exit(1)
|
|
|
|
# Display general settings
|
|
general_table = Table(title="General Settings")
|
|
general_table.add_column("Setting", style="cyan")
|
|
general_table.add_column("Value", style="green")
|
|
|
|
general_table.add_row(
|
|
"Default Provider",
|
|
str(trae_agent_config.model.model_provider.provider or "Not set"),
|
|
)
|
|
general_table.add_row("Max Steps", str(trae_agent_config.max_steps or "Not set"))
|
|
|
|
console.print(general_table)
|
|
|
|
# Display provider settings
|
|
provider_config = trae_agent_config.model.model_provider
|
|
provider_table = Table(title=f"{provider_config.provider.title()} Configuration")
|
|
provider_table.add_column("Setting", style="cyan")
|
|
provider_table.add_column("Value", style="green")
|
|
|
|
provider_table.add_row("Model", trae_agent_config.model.model or "Not set")
|
|
provider_table.add_row("Base URL", provider_config.base_url or "Not set")
|
|
provider_table.add_row("API Version", provider_config.api_version or "Not set")
|
|
provider_table.add_row(
|
|
"API Key",
|
|
(
|
|
f"Set ({provider_config.api_key[:4]}...{provider_config.api_key[-4:]})"
|
|
if provider_config.api_key
|
|
else "Not set"
|
|
),
|
|
)
|
|
provider_table.add_row("Max Tokens", str(trae_agent_config.model.max_tokens))
|
|
provider_table.add_row("Temperature", str(trae_agent_config.model.temperature))
|
|
provider_table.add_row("Top P", str(trae_agent_config.model.top_p))
|
|
|
|
if trae_agent_config.model.model_provider.provider == "anthropic":
|
|
provider_table.add_row("Top K", str(trae_agent_config.model.top_k))
|
|
|
|
console.print(provider_table)
|
|
|
|
|
|
@cli.command()
|
|
def tools():
|
|
"""Show available tools and their descriptions."""
|
|
from .tools import tools_registry
|
|
|
|
tools_table = Table(title="Available Tools")
|
|
tools_table.add_column("Tool Name", style="cyan")
|
|
tools_table.add_column("Description", style="green")
|
|
|
|
for tool_name in tools_registry:
|
|
try:
|
|
tool = tools_registry[tool_name]()
|
|
tools_table.add_row(tool.name, tool.description)
|
|
except Exception as e:
|
|
tools_table.add_row(tool_name, f"[red]Error loading: {e}[/red]")
|
|
|
|
console.print(tools_table)
|
|
|
|
|
|
def main():
|
|
"""Main entry point for the CLI."""
|
|
cli()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|