diff --git a/lib/crewai/pyproject.toml b/lib/crewai/pyproject.toml index ada287cd8..6e9a1f2a1 100644 --- a/lib/crewai/pyproject.toml +++ b/lib/crewai/pyproject.toml @@ -10,7 +10,7 @@ requires-python = ">=3.10, <3.14" dependencies = [ # Core Dependencies "pydantic~=2.11.9", - "openai~=1.83.0", + "openai>=1.83.0,<2", "instructor>=1.3.3", # Text Processing "pdfplumber~=0.11.4", diff --git a/lib/crewai/tests/test_dependency_constraints.py b/lib/crewai/tests/test_dependency_constraints.py new file mode 100644 index 000000000..e0f59c444 --- /dev/null +++ b/lib/crewai/tests/test_dependency_constraints.py @@ -0,0 +1,91 @@ +"""Test that dependency constraints are compatible with common integrations.""" + +import tomllib +from pathlib import Path + +from packaging.specifiers import SpecifierSet +from packaging.version import Version + + +def get_pyproject_dependencies() -> dict[str, str]: + """Parse pyproject.toml and return dependencies as a dict.""" + pyproject_path = Path(__file__).parent.parent / "pyproject.toml" + with open(pyproject_path, "rb") as f: + data = tomllib.load(f) + + dependencies = {} + for dep in data.get("project", {}).get("dependencies", []): + if ">=" in dep or "~=" in dep or "==" in dep or "<" in dep: + parts = dep.replace(">=", " ").replace("~=", " ").replace("==", " ").replace(",", " ").replace("<", " <").split() + if parts: + name = parts[0].strip() + constraint = dep[len(name):].strip() + dependencies[name] = constraint + return dependencies + + +def test_openai_constraint_allows_openlit_compatible_versions(): + """Test that openai constraint allows versions >= 1.92.0 required by OpenLit. + + This test ensures that the openai dependency constraint is relaxed enough + to allow integration with OpenLit, which requires openai >= 1.92.0. + + See: https://github.com/crewAIInc/crewAI/issues/4270 + """ + dependencies = get_pyproject_dependencies() + + assert "openai" in dependencies, "openai should be in dependencies" + + openai_constraint = dependencies["openai"] + specifier = SpecifierSet(openai_constraint) + + openlit_required_version = Version("1.92.0") + assert openlit_required_version in specifier, ( + f"openai constraint '{openai_constraint}' should allow version 1.92.0 " + f"required by OpenLit. Current constraint blocks OpenLit integration." + ) + + higher_1x_version = Version("1.109.0") + assert higher_1x_version in specifier, ( + f"openai constraint '{openai_constraint}' should allow higher 1.x versions" + ) + + +def test_openai_constraint_has_upper_bound(): + """Test that openai constraint has an upper bound to prevent breaking changes. + + The constraint should prevent openai 2.x which may have breaking changes. + """ + dependencies = get_pyproject_dependencies() + + assert "openai" in dependencies, "openai should be in dependencies" + + openai_constraint = dependencies["openai"] + specifier = SpecifierSet(openai_constraint) + + version_2 = Version("2.0.0") + assert version_2 not in specifier, ( + f"openai constraint '{openai_constraint}' should NOT allow version 2.0.0 " + f"to prevent potential breaking changes from major version bump" + ) + + +def test_openai_constraint_minimum_version(): + """Test that openai constraint has a reasonable minimum version.""" + dependencies = get_pyproject_dependencies() + + assert "openai" in dependencies, "openai should be in dependencies" + + openai_constraint = dependencies["openai"] + specifier = SpecifierSet(openai_constraint) + + min_version = Version("1.83.0") + assert min_version in specifier, ( + f"openai constraint '{openai_constraint}' should allow version 1.83.0" + ) + + old_version = Version("1.82.0") + assert old_version not in specifier, ( + f"openai constraint '{openai_constraint}' should NOT allow version 1.82.0 " + f"which is below the minimum required version" + )