mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-08 15:48:29 +00:00
316 lines
12 KiB
Python
316 lines
12 KiB
Python
import sys
|
|
import os
|
|
import subprocess
|
|
from typing import Dict, Any
|
|
|
|
import click
|
|
import requests
|
|
from rich.console import Console
|
|
from rich.table import Table
|
|
from rich.text import Text
|
|
|
|
from crewai.cli.command import BaseCommand, PlusAPIMixin
|
|
from crewai.telemetry.telemetry import Telemetry
|
|
|
|
console = Console()
|
|
|
|
|
|
class TriggerCommand(BaseCommand, PlusAPIMixin):
|
|
"""Command handler for trigger-related operations."""
|
|
|
|
def __init__(self):
|
|
"""Initialize the trigger command with telemetry and API client."""
|
|
self._telemetry = Telemetry()
|
|
super().__init__()
|
|
PlusAPIMixin.__init__(self, self._telemetry)
|
|
|
|
def list_triggers(self) -> None:
|
|
"""List all triggers grouped by provider name."""
|
|
try:
|
|
console.print("Fetching triggers from CrewAI API...", style="blue")
|
|
|
|
# Fetch triggers from API
|
|
response = self.plus_api_client.list_triggers()
|
|
self._validate_response(response)
|
|
|
|
triggers_data = response.json()
|
|
|
|
if not triggers_data:
|
|
console.print(
|
|
"No triggers found for the current user.", style="yellow"
|
|
)
|
|
return
|
|
|
|
# Display triggers grouped by provider
|
|
self._display_triggers(triggers_data)
|
|
|
|
except requests.exceptions.ConnectionError:
|
|
console.print(
|
|
"Failed to connect to CrewAI API. Please check your internet connection.",
|
|
style="bold red"
|
|
)
|
|
raise SystemExit(1)
|
|
except requests.exceptions.Timeout:
|
|
console.print(
|
|
"Request to CrewAI API timed out. Please try again later.",
|
|
style="bold red"
|
|
)
|
|
raise SystemExit(1)
|
|
except requests.exceptions.HTTPError as e:
|
|
if e.response.status_code == 401:
|
|
console.print(
|
|
"Authentication failed. Please run 'crewai login' to authenticate.",
|
|
style="bold red"
|
|
)
|
|
elif e.response.status_code == 403:
|
|
console.print(
|
|
"Access denied. You may not have permission to access triggers.",
|
|
style="bold red"
|
|
)
|
|
else:
|
|
console.print(f"HTTP error occurred: {e}", style="bold red")
|
|
raise SystemExit(1)
|
|
except Exception as e:
|
|
console.print(f"Unexpected error listing triggers: {e}", style="bold red")
|
|
console.print("Please check your configuration and try again.", style="yellow")
|
|
raise SystemExit(1)
|
|
|
|
def run_trigger(self, trigger_identification: str) -> None:
|
|
"""Run a crew with the specified trigger payload."""
|
|
try:
|
|
# Validate trigger identification format
|
|
if not trigger_identification or "/" not in trigger_identification:
|
|
console.print(
|
|
"Invalid trigger identification format. Expected format: 'app/trigger_name'",
|
|
style="bold red"
|
|
)
|
|
console.print(
|
|
"Use 'crewai trigger list' to see available triggers.", style="yellow"
|
|
)
|
|
raise SystemExit(1)
|
|
|
|
# Get sample payload for the trigger
|
|
console.print(f"Getting sample payload for trigger: {trigger_identification}", style="blue")
|
|
response = self.plus_api_client.get_trigger_sample_payload(trigger_identification)
|
|
self._validate_response(response)
|
|
|
|
trigger_payload = response.json()
|
|
|
|
if not trigger_payload:
|
|
console.print(
|
|
f"No sample payload found for trigger: {trigger_identification}",
|
|
style="yellow"
|
|
)
|
|
console.print(
|
|
"Use 'crewai trigger list' to see available triggers.", style="yellow"
|
|
)
|
|
return
|
|
|
|
console.print("Sample payload retrieved successfully", style="green")
|
|
|
|
# Import and run the crew with the trigger payload
|
|
self._run_crew_with_payload(trigger_payload)
|
|
|
|
except requests.exceptions.ConnectionError:
|
|
console.print(
|
|
"Failed to connect to CrewAI API. Please check your internet connection.",
|
|
style="bold red"
|
|
)
|
|
raise SystemExit(1)
|
|
except requests.exceptions.Timeout:
|
|
console.print(
|
|
"Request to CrewAI API timed out. Please try again later.",
|
|
style="bold red"
|
|
)
|
|
raise SystemExit(1)
|
|
except requests.exceptions.HTTPError as e:
|
|
if e.response.status_code == 401:
|
|
console.print(
|
|
"Authentication failed. Please run 'crewai login' to authenticate.",
|
|
style="bold red"
|
|
)
|
|
elif e.response.status_code == 404:
|
|
console.print(
|
|
f"Trigger '{trigger_identification}' not found.",
|
|
style="bold red"
|
|
)
|
|
console.print(
|
|
"Use 'crewai trigger list' to see available triggers.", style="yellow"
|
|
)
|
|
elif e.response.status_code == 403:
|
|
console.print(
|
|
"Access denied. You may not have permission to access this trigger.",
|
|
style="bold red"
|
|
)
|
|
else:
|
|
console.print(f"HTTP error occurred: {e}", style="bold red")
|
|
raise SystemExit(1)
|
|
except FileNotFoundError as e:
|
|
console.print(
|
|
f"Project file not found: {e}", style="bold red"
|
|
)
|
|
console.print(
|
|
"Make sure you're in a valid CrewAI project directory.", style="yellow"
|
|
)
|
|
raise SystemExit(1)
|
|
except subprocess.CalledProcessError as e:
|
|
console.print(f"Error running crew: {e}", style="bold red")
|
|
if e.output:
|
|
console.print(f"Output: {e.output}", style="red")
|
|
raise SystemExit(1)
|
|
except Exception as e:
|
|
console.print(f"Unexpected error running trigger: {e}", style="bold red")
|
|
console.print("Please check your configuration and try again.", style="yellow")
|
|
raise SystemExit(1)
|
|
|
|
def _display_triggers(self, triggers_data: Dict[str, Any]) -> None:
|
|
"""Display triggers in a formatted table grouped by provider."""
|
|
table = Table(title="Available Triggers")
|
|
table.add_column("Provider", style="cyan", no_wrap=True)
|
|
table.add_column("Trigger ID", style="magenta")
|
|
table.add_column("Description", style="green")
|
|
|
|
# Group triggers by provider
|
|
for provider_name, triggers in triggers_data.items():
|
|
if isinstance(triggers, dict):
|
|
# Add provider header
|
|
first_trigger = True
|
|
|
|
for trigger_id, trigger_info in triggers.items():
|
|
description = trigger_info.get("description", "No description available")
|
|
|
|
# Display provider name only for the first trigger of each provider
|
|
provider_display = provider_name if first_trigger else ""
|
|
first_trigger = False
|
|
|
|
table.add_row(
|
|
provider_display,
|
|
trigger_id,
|
|
description
|
|
)
|
|
|
|
# Add separator between providers (except for the last one)
|
|
if provider_name != list(triggers_data.keys())[-1]:
|
|
table.add_row("", "", "")
|
|
|
|
console.print(table)
|
|
console.print("\nTo run a trigger, use: [bold green]crewai trigger <trigger_id>[/bold green]")
|
|
|
|
def _run_crew_with_payload(self, trigger_payload: Dict[str, Any]) -> None:
|
|
"""Run the crew with the trigger payload."""
|
|
script_path = None
|
|
try:
|
|
from crewai.cli.utils import read_toml
|
|
|
|
# Validate project structure
|
|
if not os.path.exists("pyproject.toml"):
|
|
raise FileNotFoundError("pyproject.toml not found. Make sure you're in a CrewAI project directory.")
|
|
|
|
if not os.path.exists("src"):
|
|
raise FileNotFoundError("src directory not found. Make sure you're in a CrewAI project directory.")
|
|
|
|
if not os.path.exists("src/main.py"):
|
|
raise FileNotFoundError("src/main.py not found. Make sure you have a valid CrewAI project.")
|
|
|
|
# Read project configuration
|
|
pyproject_data = read_toml()
|
|
is_flow = pyproject_data.get("tool", {}).get("crewai", {}).get("type") == "flow"
|
|
|
|
console.print(f"Project type detected: {'Flow' if is_flow else 'Crew'}")
|
|
console.print("Preparing execution environment...")
|
|
|
|
# Create a temporary script to run the crew with trigger payload
|
|
script_content = self._generate_crew_script(trigger_payload, is_flow)
|
|
|
|
# Write script to temporary file
|
|
script_path = "temp_trigger_run.py"
|
|
with open(script_path, "w") as f:
|
|
f.write(script_content)
|
|
|
|
console.print(f"Running {'flow' if is_flow else 'crew'} with trigger payload...", style="blue")
|
|
|
|
# Execute the script
|
|
command = ["uv", "run", "python", script_path]
|
|
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
|
|
|
# Display success message
|
|
console.print("✓ Execution completed successfully!", style="bold green")
|
|
if result.stdout:
|
|
console.print("Output:", style="blue")
|
|
console.print(result.stdout)
|
|
|
|
except FileNotFoundError as e:
|
|
raise # Re-raise to be caught by the outer try-catch
|
|
except subprocess.CalledProcessError as e:
|
|
error_msg = f"Crew execution failed with exit code {e.returncode}"
|
|
if e.stderr:
|
|
error_msg += f"\nError output: {e.stderr}"
|
|
if e.stdout:
|
|
error_msg += f"\nStandard output: {e.stdout}"
|
|
raise subprocess.CalledProcessError(e.returncode, e.cmd, error_msg)
|
|
except Exception as e:
|
|
raise Exception(f"Failed to execute crew: {str(e)}")
|
|
finally:
|
|
# Clean up temporary script
|
|
if script_path and os.path.exists(script_path):
|
|
try:
|
|
os.remove(script_path)
|
|
except OSError:
|
|
console.print(f"Warning: Could not remove temporary file {script_path}", style="yellow")
|
|
|
|
def _generate_crew_script(self, trigger_payload: Dict[str, Any], is_flow: bool) -> str:
|
|
"""Generate a Python script to run the crew with trigger payload."""
|
|
if is_flow:
|
|
return f"""
|
|
import sys
|
|
sys.path.append('src')
|
|
|
|
from main import *
|
|
|
|
def main():
|
|
try:
|
|
# Initialize and run the flow with trigger payload
|
|
flow = main()
|
|
|
|
# Add trigger payload to inputs
|
|
inputs = {{"crewai_trigger_payload": {trigger_payload}}}
|
|
|
|
result = flow.kickoff(inputs=inputs)
|
|
print("Flow execution completed successfully")
|
|
print(f"Result: {{result}}")
|
|
|
|
except Exception as e:
|
|
print(f"Error running flow: {{e}}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
"""
|
|
else:
|
|
return f"""
|
|
import sys
|
|
sys.path.append('src')
|
|
|
|
def main():
|
|
try:
|
|
# Import the crew
|
|
from main import main as crew_main
|
|
|
|
# Get the crew instance
|
|
crew = crew_main()
|
|
|
|
# Add trigger payload to inputs
|
|
inputs = {{"crewai_trigger_payload": {trigger_payload}}}
|
|
|
|
result = crew.kickoff(inputs=inputs)
|
|
print("Crew execution completed successfully")
|
|
print(f"Result: {{result}}")
|
|
|
|
except Exception as e:
|
|
print(f"Error running crew: {{e}}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
"""
|