Skip to content

Commit 480ad5b

Browse files
devin-ai-integration[bot]João
andcommitted
fix: relax openai version constraint to allow 2.x for litellm[proxy] compatibility
Fixes #4079 The openai version constraint was pinned to ~=1.83.0 (>=1.83.0,<1.84.0), which prevented installation alongside litellm[proxy]>=1.74.9 that requires openai>=2.8.0. Changes: - Updated openai constraint from ~=1.83.0 to >=1.83.0,<3 - Added tests to verify the constraint allows openai 2.8.0 - Added import smoke tests for OpenAI provider compatibility The new constraint: - Maintains backward compatibility with openai 1.83.x - Allows openai 2.x for users who need litellm[proxy] - Caps at <3 to prevent future breaking changes Verified that all OpenAI SDK imports used by crewAI's OpenAI provider work correctly with openai 2.8.0. Co-Authored-By: João <joao@crewai.com>
1 parent 38b0b12 commit 480ad5b

File tree

3 files changed

+4439
-4226
lines changed

3 files changed

+4439
-4226
lines changed

lib/crewai/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ requires-python = ">=3.10, <3.14"
1010
dependencies = [
1111
# Core Dependencies
1212
"pydantic~=2.11.9",
13-
"openai~=1.83.0",
13+
"openai>=1.83.0,<3",
1414
"instructor>=1.3.3",
1515
# Text Processing
1616
"pdfplumber~=0.11.4",
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
"""Tests for OpenAI SDK version compatibility.
2+
3+
These tests verify that crewAI's openai dependency constraint allows
4+
installation alongside packages that require openai 2.x (like litellm[proxy]).
5+
6+
Related to GitHub issue #4079: CrewAI dependency conflict with litellm[proxy]
7+
"""
8+
9+
import sys
10+
from pathlib import Path
11+
12+
import pytest
13+
from packaging.specifiers import SpecifierSet
14+
15+
16+
def test_openai_version_constraint_allows_2x():
17+
"""Test that the openai version constraint in pyproject.toml allows openai 2.x.
18+
19+
This test verifies the fix for issue #4079 where crewAI could not be installed
20+
alongside litellm[proxy]>=1.74.9 due to conflicting openai version requirements.
21+
22+
The constraint should allow openai>=1.83.0,<3 to support both:
23+
- Existing users on openai 1.83.x
24+
- Users who need openai 2.x for litellm[proxy] compatibility
25+
"""
26+
try:
27+
import tomllib
28+
except ImportError:
29+
import tomli as tomllib
30+
31+
# Find the pyproject.toml file
32+
tests_dir = Path(__file__).parent
33+
pyproject_path = tests_dir.parent / "pyproject.toml"
34+
35+
with open(pyproject_path, "rb") as f:
36+
pyproject = tomllib.load(f)
37+
38+
dependencies = pyproject.get("project", {}).get("dependencies", [])
39+
40+
# Find the openai dependency
41+
openai_dep = None
42+
for dep in dependencies:
43+
if dep.startswith("openai"):
44+
openai_dep = dep
45+
break
46+
47+
assert openai_dep is not None, "openai dependency not found in pyproject.toml"
48+
49+
# Extract the version specifier from the dependency string
50+
# e.g., "openai>=1.83.0,<3" -> ">=1.83.0,<3"
51+
version_spec = openai_dep.replace("openai", "").strip()
52+
specifier = SpecifierSet(version_spec)
53+
54+
# Test that the specifier allows openai 2.8.0 (required by litellm[proxy])
55+
assert "2.8.0" in specifier, (
56+
f"openai constraint '{openai_dep}' does not allow version 2.8.0 "
57+
"which is required by litellm[proxy]>=1.74.9"
58+
)
59+
60+
# Test that the specifier still allows openai 1.83.0 (backward compatibility)
61+
assert "1.83.0" in specifier, (
62+
f"openai constraint '{openai_dep}' does not allow version 1.83.0 "
63+
"which breaks backward compatibility"
64+
)
65+
66+
# Test that the specifier has an upper bound (to prevent future breaks)
67+
assert "<3" in version_spec or "<3.0" in version_spec, (
68+
f"openai constraint '{openai_dep}' should have an upper bound <3 "
69+
"to prevent future breaking changes"
70+
)
71+
72+
73+
def test_openai_provider_imports_are_valid():
74+
"""Test that all imports used by the OpenAI provider are valid.
75+
76+
This test verifies that the OpenAI SDK exports all the classes and types
77+
that crewAI's OpenAI provider depends on. This ensures compatibility
78+
across different openai SDK versions.
79+
"""
80+
# Test core client imports
81+
from openai import APIConnectionError, AsyncOpenAI, NotFoundError, OpenAI, Stream
82+
83+
assert OpenAI is not None
84+
assert AsyncOpenAI is not None
85+
assert Stream is not None
86+
assert APIConnectionError is not None
87+
assert NotFoundError is not None
88+
89+
# Test streaming imports
90+
from openai.lib.streaming.chat import ChatCompletionStream
91+
92+
assert ChatCompletionStream is not None
93+
94+
# Test type imports
95+
from openai.types.chat import ChatCompletion, ChatCompletionChunk
96+
from openai.types.chat.chat_completion import Choice
97+
from openai.types.chat.chat_completion_chunk import ChoiceDelta
98+
99+
assert ChatCompletion is not None
100+
assert ChatCompletionChunk is not None
101+
assert Choice is not None
102+
assert ChoiceDelta is not None
103+
104+
105+
def test_openai_client_instantiation():
106+
"""Test that OpenAI clients can be instantiated with a test API key.
107+
108+
This verifies that the OpenAI SDK client initialization is compatible
109+
with crewAI's usage patterns.
110+
"""
111+
from openai import AsyncOpenAI, OpenAI
112+
113+
# Test sync client instantiation
114+
client = OpenAI(api_key="test-key-for-instantiation-test")
115+
assert client is not None
116+
assert hasattr(client, "chat")
117+
assert hasattr(client.chat, "completions")
118+
119+
# Test async client instantiation
120+
async_client = AsyncOpenAI(api_key="test-key-for-instantiation-test")
121+
assert async_client is not None
122+
assert hasattr(async_client, "chat")
123+
assert hasattr(async_client.chat, "completions")
124+
125+
126+
def test_openai_completion_provider_can_be_imported():
127+
"""Test that crewAI's OpenAI completion provider can be imported.
128+
129+
This verifies that the OpenAI provider module loads correctly with
130+
the installed openai SDK version.
131+
"""
132+
from crewai.llms.providers.openai.completion import OpenAICompletion
133+
134+
assert OpenAICompletion is not None
135+
136+
137+
def test_openai_completion_provider_instantiation():
138+
"""Test that OpenAICompletion can be instantiated.
139+
140+
This verifies that crewAI's OpenAI provider works correctly with
141+
the installed openai SDK version.
142+
"""
143+
from crewai.llms.providers.openai.completion import OpenAICompletion
144+
145+
# Instantiate with a test API key
146+
completion = OpenAICompletion(
147+
model="gpt-4o",
148+
api_key="test-key-for-instantiation-test",
149+
)
150+
151+
assert completion is not None
152+
assert completion.model == "gpt-4o"
153+
assert completion.client is not None
154+
assert completion.async_client is not None

0 commit comments

Comments
 (0)