mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-02 05:38:12 +00:00
Consolidate crewai run and crewai flow kickoff (#6296)
Make `crewai run` the single execution path for crews and flows, with `crewai flow kickoff` kept as a deprecated compatibility alias.
This commit is contained in:
@@ -40,14 +40,6 @@ def replay_task_command(*args: Any, **kwargs: Any) -> Any:
|
||||
return _replay_task_command(*args, **kwargs)
|
||||
|
||||
|
||||
def run_declarative_flow(*args: Any, **kwargs: Any) -> Any:
|
||||
from crewai_cli.run_declarative_flow import (
|
||||
run_declarative_flow as _run_declarative_flow,
|
||||
)
|
||||
|
||||
return _run_declarative_flow(*args, **kwargs)
|
||||
|
||||
|
||||
def run_crew(*args: Any, **kwargs: Any) -> Any:
|
||||
from crewai_cli.run_crew import run_crew as _run_crew
|
||||
|
||||
@@ -476,7 +468,7 @@ def memory(
|
||||
type=str,
|
||||
default=None,
|
||||
help=(
|
||||
"Path to a trained-agents pickle (produced by `crewai train -f`). "
|
||||
"Crew-only: path to a trained-agents pickle (produced by `crewai train -f`). "
|
||||
"When set, agents load suggestions from this file instead of the "
|
||||
"default trained_agents_data.pkl. Equivalent to setting "
|
||||
"CREWAI_TRAINED_AGENTS_FILE."
|
||||
@@ -520,13 +512,13 @@ def install(context: click.Context) -> None:
|
||||
"--definition",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Experimental: path to a declarative Flow YAML/JSON file.",
|
||||
help="Flow-only: path to a declarative flow definition.",
|
||||
)
|
||||
@click.option(
|
||||
"--inputs",
|
||||
type=str,
|
||||
default=None,
|
||||
help='Experimental: JSON object passed to flow.kickoff(), e.g. \'{"topic":"AI"}\'.',
|
||||
help='Flow-only: JSON object passed to the declarative flow, e.g. \'{"topic":"AI"}\'.',
|
||||
)
|
||||
def run(
|
||||
trained_agents_file: str | None,
|
||||
@@ -536,16 +528,14 @@ def run(
|
||||
"""Run the Crew or Flow."""
|
||||
if inputs is not None and definition is None:
|
||||
raise click.UsageError("--inputs requires --definition")
|
||||
if trained_agents_file is not None and definition is not None:
|
||||
raise click.UsageError("--filename can only be used when running crews")
|
||||
|
||||
if definition is not None:
|
||||
click.secho(
|
||||
"Warning: `crewai run --definition` is experimental and may change without notice.",
|
||||
fg="yellow",
|
||||
)
|
||||
run_declarative_flow(definition=definition, inputs=inputs)
|
||||
return
|
||||
|
||||
run_crew(trained_agents_file=trained_agents_file)
|
||||
run_crew(
|
||||
trained_agents_file=trained_agents_file,
|
||||
definition=definition,
|
||||
inputs=inputs,
|
||||
)
|
||||
|
||||
|
||||
@crewai.command()
|
||||
@@ -797,13 +787,10 @@ def flow() -> None:
|
||||
"""Flow related commands."""
|
||||
|
||||
|
||||
@flow.command(name="kickoff")
|
||||
@flow.command(name="kickoff", deprecated=True)
|
||||
def flow_run() -> None:
|
||||
"""Kickoff the Flow."""
|
||||
from crewai_cli.kickoff_flow import kickoff_flow
|
||||
|
||||
click.echo("Running the Flow")
|
||||
kickoff_flow()
|
||||
run_crew(trained_agents_file=None, definition=None, inputs=None)
|
||||
|
||||
|
||||
@flow.command(name="plot")
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import subprocess
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def kickoff_flow() -> None:
|
||||
"""
|
||||
Kickoff the flow from declarative config or the Python UV entrypoint.
|
||||
"""
|
||||
from crewai_cli.run_declarative_flow import (
|
||||
configured_project_declarative_flow,
|
||||
run_declarative_flow_in_project_env,
|
||||
)
|
||||
|
||||
if definition := configured_project_declarative_flow():
|
||||
run_declarative_flow_in_project_env(definition=definition)
|
||||
else:
|
||||
command = ["uv", "run", "kickoff"]
|
||||
|
||||
try:
|
||||
subprocess.run( # noqa: S603
|
||||
command, capture_output=False, text=True, check=True
|
||||
)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
click.echo(f"An error occurred while running the flow: {e}", err=True)
|
||||
raise SystemExit(1) from e
|
||||
|
||||
except Exception as e:
|
||||
click.echo(f"An unexpected error occurred: {e}", err=True)
|
||||
raise SystemExit(1) from e
|
||||
@@ -2,7 +2,6 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from contextlib import AbstractContextManager, nullcontext
|
||||
from enum import Enum
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
@@ -27,11 +26,6 @@ if TYPE_CHECKING:
|
||||
from crewai_cli.crew_run_tui import CrewRunApp
|
||||
|
||||
|
||||
class CrewType(Enum):
|
||||
STANDARD = "standard"
|
||||
FLOW = "flow"
|
||||
|
||||
|
||||
# Must accept the same names as the kickoff interpolation pattern in
|
||||
# crewai.utilities.string_utils (_VARIABLE_PATTERN), including hyphens —
|
||||
# otherwise placeholders are interpolated at runtime but never prompted for.
|
||||
@@ -537,7 +531,11 @@ def _print_post_tui_summary(app: CrewRunApp) -> None:
|
||||
)
|
||||
|
||||
|
||||
def run_crew(trained_agents_file: str | None = None) -> None:
|
||||
def run_crew(
|
||||
trained_agents_file: str | None = None,
|
||||
definition: str | None = None,
|
||||
inputs: str | None = None,
|
||||
) -> None:
|
||||
"""Run the crew or flow.
|
||||
|
||||
Args:
|
||||
@@ -545,15 +543,90 @@ def run_crew(trained_agents_file: str | None = None) -> None:
|
||||
by ``crewai train -f``. When set, exported as
|
||||
``CREWAI_TRAINED_AGENTS_FILE`` so agents load suggestions from this
|
||||
file instead of the default ``trained_agents_data.pkl``.
|
||||
definition: Optional path to a declarative Flow definition.
|
||||
inputs: Optional JSON object passed to a declarative Flow.
|
||||
"""
|
||||
# JSON crew projects take precedence
|
||||
if inputs is not None and definition is None:
|
||||
raise click.UsageError("--inputs requires --definition")
|
||||
|
||||
if definition is not None:
|
||||
_run_explicit_declarative_flow(
|
||||
definition=definition,
|
||||
inputs=inputs,
|
||||
trained_agents_file=trained_agents_file,
|
||||
)
|
||||
return
|
||||
|
||||
if _has_json_crew():
|
||||
_run_json_crew_in_project_env(trained_agents_file=trained_agents_file)
|
||||
return
|
||||
|
||||
pyproject_data = read_toml()
|
||||
_warn_if_old_poetry_project(pyproject_data)
|
||||
project_type = _get_project_type(pyproject_data)
|
||||
|
||||
if project_type == "flow":
|
||||
_run_flow_project(
|
||||
pyproject_data=pyproject_data,
|
||||
trained_agents_file=trained_agents_file,
|
||||
)
|
||||
return
|
||||
|
||||
_run_classic_crew_project(
|
||||
pyproject_data=pyproject_data,
|
||||
trained_agents_file=trained_agents_file,
|
||||
)
|
||||
|
||||
|
||||
def _run_explicit_declarative_flow(
|
||||
definition: str, inputs: str | None, trained_agents_file: str | None
|
||||
) -> None:
|
||||
if trained_agents_file is not None:
|
||||
raise click.UsageError("--filename can only be used when running crews")
|
||||
|
||||
from crewai_cli.run_declarative_flow import run_declarative_flow
|
||||
|
||||
run_declarative_flow(definition=definition, inputs=inputs)
|
||||
|
||||
|
||||
def _run_flow_project(
|
||||
pyproject_data: dict[str, Any], trained_agents_file: str | None
|
||||
) -> None:
|
||||
if trained_agents_file is not None:
|
||||
raise click.UsageError("--filename can only be used when running crews")
|
||||
|
||||
click.echo("Running the Flow")
|
||||
from crewai_cli.run_declarative_flow import (
|
||||
configured_project_declarative_flow,
|
||||
run_declarative_flow_in_project_env,
|
||||
)
|
||||
|
||||
if definition := configured_project_declarative_flow(pyproject_data):
|
||||
run_declarative_flow_in_project_env(definition=definition)
|
||||
return
|
||||
|
||||
_execute_uv_script("kickoff", entity_type="flow")
|
||||
|
||||
|
||||
def _run_classic_crew_project(
|
||||
pyproject_data: dict[str, Any], trained_agents_file: str | None
|
||||
) -> None:
|
||||
click.echo("Running the Crew")
|
||||
_execute_uv_script(
|
||||
"run_crew",
|
||||
entity_type="crew",
|
||||
trained_agents_file=trained_agents_file,
|
||||
)
|
||||
|
||||
|
||||
def _get_project_type(pyproject_data: dict[str, Any]) -> str | None:
|
||||
project_type = pyproject_data.get("tool", {}).get("crewai", {}).get("type")
|
||||
return project_type if isinstance(project_type, str) else None
|
||||
|
||||
|
||||
def _warn_if_old_poetry_project(pyproject_data: dict[str, Any]) -> None:
|
||||
crewai_version = get_crewai_version()
|
||||
min_required_version = "0.71.0"
|
||||
pyproject_data = read_toml()
|
||||
|
||||
if pyproject_data.get("tool", {}).get("poetry") and (
|
||||
version.parse(crewai_version) < version.parse(min_required_version)
|
||||
@@ -564,25 +637,22 @@ def run_crew(trained_agents_file: str | None = None) -> None:
|
||||
fg="red",
|
||||
)
|
||||
|
||||
is_flow = pyproject_data.get("tool", {}).get("crewai", {}).get("type") == "flow"
|
||||
crew_type = CrewType.FLOW if is_flow else CrewType.STANDARD
|
||||
|
||||
click.echo(f"Running the {'Flow' if is_flow else 'Crew'}")
|
||||
|
||||
execute_command(crew_type, trained_agents_file=trained_agents_file)
|
||||
|
||||
|
||||
def execute_command(
|
||||
crew_type: CrewType, trained_agents_file: str | None = None
|
||||
def _execute_uv_script(
|
||||
script_name: str,
|
||||
*,
|
||||
entity_type: str,
|
||||
trained_agents_file: str | None = None,
|
||||
) -> None:
|
||||
"""Execute the appropriate command based on crew type.
|
||||
"""Execute a project script through uv.
|
||||
|
||||
Args:
|
||||
crew_type: The type of crew to run.
|
||||
script_name: The project script to run.
|
||||
entity_type: The user-facing entity being run.
|
||||
trained_agents_file: Optional trained-agents pickle path forwarded to
|
||||
the subprocess via the ``CREWAI_TRAINED_AGENTS_FILE`` env var.
|
||||
"""
|
||||
command = ["uv", "run", "kickoff" if crew_type == CrewType.FLOW else "run_crew"]
|
||||
command = ["uv", "run", script_name]
|
||||
|
||||
env = build_env_with_all_tool_credentials()
|
||||
if trained_agents_file:
|
||||
@@ -592,21 +662,20 @@ def execute_command(
|
||||
subprocess.run(command, capture_output=False, text=True, check=True, env=env) # noqa: S603
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
handle_error(e, crew_type)
|
||||
_handle_run_error(e, entity_type)
|
||||
|
||||
except Exception as e:
|
||||
click.echo(f"An unexpected error occurred: {e}", err=True)
|
||||
|
||||
|
||||
def handle_error(error: subprocess.CalledProcessError, crew_type: CrewType) -> None:
|
||||
def _handle_run_error(error: subprocess.CalledProcessError, entity_type: str) -> None:
|
||||
"""
|
||||
Handle subprocess errors with appropriate messaging.
|
||||
|
||||
Args:
|
||||
error: The subprocess error that occurred
|
||||
crew_type: The type of crew that was being run
|
||||
entity_type: The type of entity that was being run
|
||||
"""
|
||||
entity_type = "flow" if crew_type == CrewType.FLOW else "crew"
|
||||
click.echo(f"An error occurred while running the {entity_type}: {error}", err=True)
|
||||
|
||||
if error.output:
|
||||
|
||||
@@ -21,7 +21,7 @@ def run_declarative_flow_in_project_env(
|
||||
if inputs is not None:
|
||||
raise click.UsageError("--inputs is only supported with --definition")
|
||||
|
||||
_execute_declarative_flow_command(["uv", "run", "crewai", "flow", "kickoff"])
|
||||
_execute_declarative_flow_command(["uv", "run", "crewai", "run"])
|
||||
|
||||
|
||||
def plot_declarative_flow_in_project_env(definition: str) -> None:
|
||||
@@ -34,7 +34,7 @@ def plot_declarative_flow_in_project_env(definition: str) -> None:
|
||||
|
||||
|
||||
def run_declarative_flow(definition: str, inputs: str | None = None) -> None:
|
||||
"""Run a declarative flow from a YAML/JSON file path."""
|
||||
"""Run a declarative flow from a definition path."""
|
||||
parsed_inputs = _parse_inputs(inputs)
|
||||
|
||||
try:
|
||||
@@ -50,7 +50,7 @@ def run_declarative_flow(definition: str, inputs: str | None = None) -> None:
|
||||
|
||||
|
||||
def plot_declarative_flow(definition: str) -> None:
|
||||
"""Plot a declarative flow from a YAML/JSON file path."""
|
||||
"""Plot a declarative flow from a definition path."""
|
||||
try:
|
||||
flow = load_declarative_flow(definition)
|
||||
flow.plot()
|
||||
@@ -62,7 +62,7 @@ def plot_declarative_flow(definition: str) -> None:
|
||||
|
||||
|
||||
def load_declarative_flow(definition: str) -> Any:
|
||||
"""Load a declarative Flow instance from a YAML/JSON file path."""
|
||||
"""Load a declarative Flow instance from a definition path."""
|
||||
try:
|
||||
from crewai.flow.flow import Flow
|
||||
from crewai.flow.flow_definition import FlowDefinition
|
||||
|
||||
@@ -62,7 +62,7 @@ crewai create flow <name> --skip_provider # New flow project
|
||||
|
||||
# Running
|
||||
crewai run # Run crew or flow (auto-detects from pyproject.toml)
|
||||
crewai flow kickoff # Legacy flow execution
|
||||
crewai flow kickoff # Deprecated compatibility alias for crewai run
|
||||
|
||||
# Testing & training
|
||||
crewai test # Test crew (default: 2 iterations, gpt-4o-mini)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# {{name}} Flow
|
||||
|
||||
This project defines a CrewAI Flow in `src/{{folder_name}}/flow.yaml`.
|
||||
This project defines a declarative CrewAI Flow in `src/{{folder_name}}/flow.yaml`.
|
||||
|
||||
## Install
|
||||
|
||||
@@ -11,7 +11,7 @@ crewai install
|
||||
## Run
|
||||
|
||||
```bash
|
||||
crewai flow kickoff
|
||||
crewai run
|
||||
```
|
||||
|
||||
Edit `src/{{folder_name}}/flow.yaml` to change the flow. Add reusable crews under `src/{{folder_name}}/crews/`, custom Python tools under `src/{{folder_name}}/tools/`, and shared knowledge files under `src/{{folder_name}}/knowledge/`.
|
||||
Edit the declarative flow definition at `src/{{folder_name}}/flow.yaml` to change the flow. Add reusable crews under `src/{{folder_name}}/crews/`, custom Python tools under `src/{{folder_name}}/tools/`, and shared knowledge files under `src/{{folder_name}}/knowledge/`.
|
||||
|
||||
Reference in New Issue
Block a user