mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-01 13:18:10 +00:00
fix(cli): load json runner from source checkout
This commit is contained in:
@@ -35,12 +35,46 @@ class CrewType(Enum):
|
||||
# crewai.utilities.string_utils (_VARIABLE_PATTERN), including hyphens —
|
||||
# otherwise placeholders are interpolated at runtime but never prompted for.
|
||||
_INPUT_PLACEHOLDER_RE = re.compile(r"(?<!{){([A-Za-z_][A-Za-z0-9_\-]*)}(?!})")
|
||||
_JSON_CREW_RUNNER_CODE = (
|
||||
"import os; "
|
||||
"from crewai_core.constants import CREWAI_TRAINED_AGENTS_FILE_ENV; "
|
||||
"from crewai_cli.run_crew import _run_json_crew; "
|
||||
"_run_json_crew(trained_agents_file=os.getenv(CREWAI_TRAINED_AGENTS_FILE_ENV))"
|
||||
_CREWAI_CLI_RUNNER_PACKAGE_DIR_ENV = "CREWAI_CLI_RUNNER_PACKAGE_DIR"
|
||||
_CREWAI_RUNNER_SOURCE_DIR_ENV = "CREWAI_RUNNER_SOURCE_DIR"
|
||||
_JSON_CREW_RUNNER_CODE = """
|
||||
import importlib.util
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
source_dir = os.environ.get("CREWAI_RUNNER_SOURCE_DIR")
|
||||
if source_dir:
|
||||
sys.path.insert(0, source_dir)
|
||||
|
||||
package_dir = Path(os.environ["CREWAI_CLI_RUNNER_PACKAGE_DIR"])
|
||||
package_spec = importlib.util.spec_from_file_location(
|
||||
"crewai_cli",
|
||||
package_dir / "__init__.py",
|
||||
submodule_search_locations=[str(package_dir)],
|
||||
)
|
||||
if package_spec is None or package_spec.loader is None:
|
||||
raise ImportError(f"Cannot load CrewAI CLI package from {package_dir}")
|
||||
|
||||
package = importlib.util.module_from_spec(package_spec)
|
||||
sys.modules["crewai_cli"] = package
|
||||
package_spec.loader.exec_module(package)
|
||||
|
||||
module_path = package_dir / "run_crew.py"
|
||||
module_spec = importlib.util.spec_from_file_location("crewai_cli.run_crew", module_path)
|
||||
if module_spec is None or module_spec.loader is None:
|
||||
raise ImportError(f"Cannot load CrewAI CLI runner from {module_path}")
|
||||
|
||||
module = importlib.util.module_from_spec(module_spec)
|
||||
sys.modules["crewai_cli.run_crew"] = module
|
||||
module_spec.loader.exec_module(module)
|
||||
|
||||
from crewai_core.constants import CREWAI_TRAINED_AGENTS_FILE_ENV
|
||||
|
||||
module._run_json_crew(
|
||||
trained_agents_file=os.getenv(CREWAI_TRAINED_AGENTS_FILE_ENV)
|
||||
)
|
||||
""".strip()
|
||||
|
||||
|
||||
def _has_json_crew() -> bool:
|
||||
@@ -238,6 +272,15 @@ def _install_json_crew_dependencies() -> None:
|
||||
raise SystemExit(1) from e
|
||||
|
||||
|
||||
def _find_local_crewai_source_dir() -> Path | None:
|
||||
"""Return the repo's CrewAI source dir when running from a source checkout."""
|
||||
for parent in Path(__file__).resolve().parents:
|
||||
candidate = parent / "lib" / "crewai" / "src"
|
||||
if (candidate / "crewai" / "project" / "json_loader.py").is_file():
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def _run_json_crew_in_project_env(trained_agents_file: str | None = None) -> Any:
|
||||
"""Run JSON crews from the project's uv-managed environment."""
|
||||
if not (Path.cwd() / "pyproject.toml").is_file():
|
||||
@@ -247,6 +290,9 @@ def _run_json_crew_in_project_env(trained_agents_file: str | None = None) -> Any
|
||||
|
||||
command = ["uv", "run", "--no-sync", "python", "-c", _JSON_CREW_RUNNER_CODE]
|
||||
env = build_env_with_all_tool_credentials()
|
||||
env[_CREWAI_CLI_RUNNER_PACKAGE_DIR_ENV] = str(Path(__file__).resolve().parent)
|
||||
if local_crewai_source_dir := _find_local_crewai_source_dir():
|
||||
env[_CREWAI_RUNNER_SOURCE_DIR_ENV] = str(local_crewai_source_dir)
|
||||
if trained_agents_file:
|
||||
env[CREWAI_TRAINED_AGENTS_FILE_ENV] = trained_agents_file
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from crewai_core.constants import CREWAI_TRAINED_AGENTS_FILE_ENV
|
||||
@@ -56,6 +57,18 @@ def test_json_run_uses_project_env_when_pyproject_exists(monkeypatch, tmp_path:
|
||||
trained_agents_file="trained.pkl"
|
||||
)
|
||||
|
||||
expected_env = {
|
||||
"EXISTING": "value",
|
||||
run_crew_module._CREWAI_CLI_RUNNER_PACKAGE_DIR_ENV: str(
|
||||
Path(run_crew_module.__file__).resolve().parent
|
||||
),
|
||||
CREWAI_TRAINED_AGENTS_FILE_ENV: "trained.pkl",
|
||||
}
|
||||
if local_crewai_source_dir := run_crew_module._find_local_crewai_source_dir():
|
||||
expected_env[run_crew_module._CREWAI_RUNNER_SOURCE_DIR_ENV] = str(
|
||||
local_crewai_source_dir
|
||||
)
|
||||
|
||||
assert install_calls == [True]
|
||||
assert subprocess_calls == [
|
||||
(
|
||||
@@ -71,15 +84,60 @@ def test_json_run_uses_project_env_when_pyproject_exists(monkeypatch, tmp_path:
|
||||
"capture_output": False,
|
||||
"text": True,
|
||||
"check": True,
|
||||
"env": {
|
||||
"EXISTING": "value",
|
||||
CREWAI_TRAINED_AGENTS_FILE_ENV: "trained.pkl",
|
||||
},
|
||||
"env": expected_env,
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def test_json_runner_code_loads_current_cli_package_over_project_env(tmp_path: Path):
|
||||
old_parent = tmp_path / "old"
|
||||
old_pkg = old_parent / "crewai_cli"
|
||||
old_pkg.mkdir(parents=True)
|
||||
(old_pkg / "__init__.py").write_text("")
|
||||
(old_pkg / "run_crew.py").write_text("raise ImportError('old package used')\n")
|
||||
old_crewai_project = old_parent / "crewai" / "project"
|
||||
old_crewai_project.mkdir(parents=True)
|
||||
(old_parent / "crewai" / "__init__.py").write_text("")
|
||||
(old_crewai_project / "__init__.py").write_text("")
|
||||
(old_crewai_project / "json_loader.py").write_text(
|
||||
"raise ImportError('old crewai used')\n"
|
||||
)
|
||||
|
||||
current_pkg = tmp_path / "current" / "crewai_cli"
|
||||
current_pkg.mkdir(parents=True)
|
||||
marker = tmp_path / "marker.txt"
|
||||
(current_pkg / "__init__.py").write_text("")
|
||||
(current_pkg / "run_crew.py").write_text(
|
||||
"from pathlib import Path\n"
|
||||
"from crewai.project.json_loader import SOURCE\n"
|
||||
"def _run_json_crew(trained_agents_file=None):\n"
|
||||
f" Path({str(marker)!r}).write_text(SOURCE + ':' + (trained_agents_file or ''))\n"
|
||||
)
|
||||
current_crewai_project = tmp_path / "current_crewai_src" / "crewai" / "project"
|
||||
current_crewai_project.mkdir(parents=True)
|
||||
(tmp_path / "current_crewai_src" / "crewai" / "__init__.py").write_text("")
|
||||
(current_crewai_project / "__init__.py").write_text("")
|
||||
(current_crewai_project / "json_loader.py").write_text("SOURCE = 'current'\n")
|
||||
|
||||
env = os.environ.copy()
|
||||
env["PYTHONPATH"] = str(old_parent)
|
||||
env[run_crew_module._CREWAI_CLI_RUNNER_PACKAGE_DIR_ENV] = str(current_pkg)
|
||||
env[run_crew_module._CREWAI_RUNNER_SOURCE_DIR_ENV] = str(
|
||||
tmp_path / "current_crewai_src"
|
||||
)
|
||||
env[CREWAI_TRAINED_AGENTS_FILE_ENV] = "trained.pkl"
|
||||
|
||||
subprocess.run(
|
||||
[sys.executable, "-c", run_crew_module._JSON_CREW_RUNNER_CODE],
|
||||
check=True,
|
||||
env=env,
|
||||
cwd=tmp_path,
|
||||
)
|
||||
|
||||
assert marker.read_text() == "current:trained.pkl"
|
||||
|
||||
|
||||
def test_json_run_without_pyproject_runs_in_process(monkeypatch, tmp_path: Path):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
called: dict = {}
|
||||
|
||||
Reference in New Issue
Block a user