Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/cli/src/crewai_cli/create_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import click
from crewai_core.telemetry import Telemetry

from crewai_cli.version import get_crewai_tools_dependency


DECLARATIVE_FLOW_FOLDERS = ("crews", "tools", "knowledge", "skills")

Expand Down Expand Up @@ -71,6 +73,9 @@ def process_file(src_file: Path, dst_file: Path) -> None:
content = content.replace("{{name}}", name)
content = content.replace("{{flow_name}}", class_name)
content = content.replace("{{folder_name}}", folder_name)
content = content.replace(
"{{crewai_tools_dependency}}", get_crewai_tools_dependency()
)

with open(dst_file, "w") as file:
file.write(content)
Expand Down Expand Up @@ -138,6 +143,9 @@ def _create_declarative_flow(
content = content.replace("{{name}}", name)
content = content.replace("{{flow_name}}", class_name)
content = content.replace("{{folder_name}}", folder_name)
content = content.replace(
"{{crewai_tools_dependency}}", get_crewai_tools_dependency()
)
dst_file.write_text(content, encoding="utf-8")

(project_root / ".env").write_text("OPENAI_API_KEY=YOUR_API_KEY", encoding="utf-8")
Expand Down
9 changes: 7 additions & 2 deletions lib/cli/src/crewai_cli/create_json_crew.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
load_env_vars,
write_env_file,
)
from crewai_cli.version import get_crewai_tools_dependency


# ── Provider / model data ───────────────────────────────────────
Expand Down Expand Up @@ -89,7 +90,7 @@
authors = [{{ name = "Your Name", email = "you@example.com" }}]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.14.8a1"
"{crewai_tools_dependency}"
]

[build-system]
Expand Down Expand Up @@ -1134,7 +1135,11 @@ def create_json_crew(

# Write pyproject.toml
(folder_path / "pyproject.toml").write_text(
_PYPROJECT_TOML.format(folder_name=folder_name, name=name),
_PYPROJECT_TOML.format(
folder_name=folder_name,
name=name,
crewai_tools_dependency=get_crewai_tools_dependency(),
),
encoding="utf-8",
)

Expand Down
8 changes: 4 additions & 4 deletions lib/cli/src/crewai_cli/run_crew.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
is_dmn_mode_enabled,
read_toml,
)
from crewai_cli.version import get_crewai_version
from crewai_cli.version import get_crewai_tools_dependency, get_crewai_version


if TYPE_CHECKING:
Expand All @@ -32,12 +32,12 @@
_INPUT_PLACEHOLDER_RE = re.compile(r"(?<!{){([A-Za-z_][A-Za-z0-9_\-]*)}(?!})")
_CREWAI_CLI_RUNNER_PACKAGE_DIR_ENV = "CREWAI_CLI_RUNNER_PACKAGE_DIR"
_CREWAI_RUNNER_SOURCE_DIR_ENV = "CREWAI_RUNNER_SOURCE_DIR"
_FULL_CREWAI_INSTALL_MESSAGE = """\
_FULL_CREWAI_INSTALL_MESSAGE = f"""\
CrewAI CLI is installed without the `crewai` package required to run crews.

Install the full CrewAI prerelease package:
Install the full CrewAI package:

uv tool install --force --prerelease=allow 'crewai[tools]==1.14.8a1'
uv tool install --force '{get_crewai_tools_dependency()}'

The quotes are required in zsh so `crewai[tools]` is not treated as a glob.
"""
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/src/crewai_cli/templates/crew/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.15.0"
"{{crewai_tools_dependency}}"
]

[project.scripts]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.15.0"
"{{crewai_tools_dependency}}"
]

[build-system]
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/src/crewai_cli/templates/flow/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.15.0"
"{{crewai_tools_dependency}}"
]

[project.scripts]
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/src/crewai_cli/templates/tool/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
readme = "README.md"
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.15.0"
"{{crewai_tools_dependency}}"
]

[tool.crewai]
Expand Down
4 changes: 4 additions & 0 deletions lib/cli/src/crewai_cli/tools/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
tree_copy,
tree_find_and_replace,
)
from crewai_cli.version import get_crewai_tools_dependency


console = Console()
Expand Down Expand Up @@ -81,6 +82,9 @@ def create(self, handle: str) -> None:
tree_copy(template_dir, project_root)
tree_find_and_replace(project_root, "{{folder_name}}", folder_name)
tree_find_and_replace(project_root, "{{class_name}}", class_name)
tree_find_and_replace(
project_root, "{{crewai_tools_dependency}}", get_crewai_tools_dependency()
)

agents_md_src = Path(__file__).parent.parent / "templates" / "AGENTS.md"
if agents_md_src.exists():
Expand Down
5 changes: 5 additions & 0 deletions lib/cli/src/crewai_cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
)
from rich.console import Console

from crewai_cli.version import get_crewai_tools_dependency


__all__ = [
"build_env_with_all_tool_credentials",
Expand Down Expand Up @@ -73,6 +75,9 @@ def copy_template(
content = content.replace("{{name}}", name)
content = content.replace("{{crew_name}}", class_name)
content = content.replace("{{folder_name}}", folder_name)
content = content.replace(
"{{crewai_tools_dependency}}", get_crewai_tools_dependency()
)

with open(dst, "w") as file:
file.write(content)
Expand Down
16 changes: 16 additions & 0 deletions lib/cli/src/crewai_cli/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,26 @@
is_current_version_yanked as is_current_version_yanked,
is_newer_version_available as is_newer_version_available,
)
from packaging.version import Version

from crewai_cli import __version__ as _crewai_cli_version


def get_crewai_dependency_range(current_version: str | None = None) -> str:
"""Return the supported CrewAI dependency range for generated projects."""
parsed_version = Version(current_version or _crewai_cli_version)
return f">={parsed_version},<{parsed_version.major + 1}.0.0"


def get_crewai_tools_dependency(current_version: str | None = None) -> str:
"""Return the generated-project dependency for CrewAI with tools."""
return f"crewai[tools]{get_crewai_dependency_range(current_version)}"


__all__ = [
"check_version",
"get_crewai_dependency_range",
"get_crewai_tools_dependency",
"get_crewai_version",
"get_latest_version_from_pypi",
"is_current_version_yanked",
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/tests/deploy/test_archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def test_create_project_zip_keeps_json_project_root_shape(tmp_path: Path):
[project]
name = "json_crew"
version = "0.1.0"
dependencies = ["crewai[tools]==1.14.8a1"]
dependencies = ["crewai[tools]>=1.15.0,<2.0.0"]

[tool.crewai]
type = "crew"
Expand Down
5 changes: 3 additions & 2 deletions lib/cli/tests/test_create_crew.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,8 +735,9 @@ def test_json_create_provider_preselects_default_model(tmp_path, monkeypatch):

pyproject = tomli.loads((tmp_path / "json_crew" / "pyproject.toml").read_text())
dependency = pyproject["project"]["dependencies"][0]
assert dependency == "crewai[tools]==1.14.8a1"
assert Version("1.14.8a1") in Requirement(dependency).specifier
assert dependency == "crewai[tools]>=1.15.0,<2.0.0"
assert Version("1.15.0") in Requirement(dependency).specifier
assert Version("2.0.0") not in Requirement(dependency).specifier
assert pyproject["tool"]["hatch"]["build"]["targets"]["wheel"][
"only-include"
] == ["agents", "crew.jsonc", "tools", "knowledge", "skills"]
Expand Down
5 changes: 1 addition & 4 deletions lib/cli/tests/test_run_crew.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ def missing_crewai_package():

message = exc_info.value.message
assert "CrewAI CLI is installed without the `crewai` package" in message
assert (
"uv tool install --force --prerelease=allow 'crewai[tools]==1.14.8a1'"
in message
)
assert "uv tool install --force 'crewai[tools]>=1.15.0,<2.0.0'" in message
assert "quotes are required in zsh" in message


Expand Down
7 changes: 7 additions & 0 deletions lib/cli/tests/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

from crewai_cli.version import get_crewai_version as _get_ver
from crewai_cli.version import (
get_crewai_dependency_range,
get_crewai_tools_dependency,
get_crewai_version,
get_latest_version_from_pypi,
is_current_version_yanked,
Expand All @@ -31,6 +33,11 @@ def test_dynamic_versioning_consistency() -> None:
assert len(package_version.strip()) > 0


def test_generated_project_dependency_uses_next_major_upper_bound() -> None:
assert get_crewai_dependency_range("1.15.0") == ">=1.15.0,<2.0.0"
assert get_crewai_tools_dependency("1.15.0") == "crewai[tools]>=1.15.0,<2.0.0"


class TestVersionChecking:
"""Test version checking utilities."""

Expand Down
4 changes: 4 additions & 0 deletions lib/cli/tests/tools/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ def test_create_success(mock_subprocess, capsys, tool_command):
)
assert os.path.isfile(os.path.join("test_tool", "src", "test_tool", "tool.py"))

with open(os.path.join("test_tool", "pyproject.toml"), "r") as f:
content = f.read()
assert '"crewai[tools]>=1.15.0,<2.0.0"' in content

with open(os.path.join("test_tool", "src", "test_tool", "tool.py"), "r") as f:
content = f.read()
assert "class TestTool" in content
Expand Down
Loading