Compare commits

..

1 Commits

Author SHA1 Message Date
Devin AI
78de2038d7 fix: relax openai version constraint to allow newer SDK versions
- Change openai dependency from ~=1.83.0 to >=1.83.0,<2
- Add tests to verify OpenAI SDK imports compatibility
- Add test to verify OpenAI client instantiation

Fixes #4300

Co-Authored-By: João <joao@crewai.com>
2026-01-29 08:46:53 +00:00
6 changed files with 62 additions and 52 deletions

View File

@@ -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",

View File

@@ -80,6 +80,7 @@ class QdrantClient(BaseClient):
optimizers_config: Optional optimizer configuration.
wal_config: Optional write-ahead log configuration.
quantization_config: Optional quantization configuration.
init_from: Optional collection to initialize from.
timeout: Optional timeout for the operation.
Raises:
@@ -119,6 +120,7 @@ class QdrantClient(BaseClient):
optimizers_config: Optional optimizer configuration.
wal_config: Optional write-ahead log configuration.
quantization_config: Optional quantization configuration.
init_from: Optional collection to initialize from.
timeout: Optional timeout for the operation.
Raises:
@@ -158,6 +160,7 @@ class QdrantClient(BaseClient):
optimizers_config: Optional optimizer configuration.
wal_config: Optional write-ahead log configuration.
quantization_config: Optional quantization configuration.
init_from: Optional collection to initialize from.
timeout: Optional timeout for the operation.
Returns:
@@ -201,6 +204,7 @@ class QdrantClient(BaseClient):
optimizers_config: Optional optimizer configuration.
wal_config: Optional write-ahead log configuration.
quantization_config: Optional quantization configuration.
init_from: Optional collection to initialize from.
timeout: Optional timeout for the operation.
Returns:

View File

@@ -16,6 +16,7 @@ from qdrant_client.models import ( # type: ignore[import-not-found]
HasIdCondition,
HasVectorCondition,
HnswConfigDiff,
InitFrom,
IsEmptyCondition,
IsNullCondition,
NestedCondition,
@@ -128,6 +129,7 @@ class CommonCreateFields(TypedDict, total=False):
optimizers_config: OptimizersConfigDiff
wal_config: WalConfigDiff
quantization_config: QuantizationConfig
init_from: InitFrom | str
timeout: Annotated[int, "Operation timeout in seconds"]

View File

@@ -113,6 +113,8 @@ def _get_collection_params(
params["wal_config"] = kwargs["wal_config"]
if "quantization_config" in kwargs:
params["quantization_config"] = kwargs["quantization_config"]
if "init_from" in kwargs:
params["init_from"] = kwargs["init_from"]
if "timeout" in kwargs:
params["timeout"] = kwargs["timeout"]

View File

@@ -1397,3 +1397,56 @@ def test_openai_responses_api_both_auto_chains_work_together():
assert params.get("previous_response_id") == "resp_123"
assert "reasoning.encrypted_content" in params["include"]
assert len(params["input"]) == 2 # Reasoning item + message
def test_openai_sdk_imports_compatibility():
"""
Test that all OpenAI SDK imports used by CrewAI are available.
This test verifies that the OpenAI SDK version installed provides all the
types and classes that CrewAI depends on. If this test fails after updating
the OpenAI SDK, it indicates a breaking change in the SDK that needs to be
addressed.
Related to issue #4300: Dependency constraints in pyproject.toml are overly strict
"""
from openai import APIConnectionError, AsyncOpenAI, NotFoundError, OpenAI, Stream
from openai.lib.streaming.chat import ChatCompletionStream
from openai.types.chat import ChatCompletion, ChatCompletionChunk
from openai.types.chat.chat_completion import Choice
from openai.types.chat.chat_completion_chunk import ChoiceDelta
from openai.types.responses import Response
assert OpenAI is not None
assert AsyncOpenAI is not None
assert Stream is not None
assert APIConnectionError is not None
assert NotFoundError is not None
assert ChatCompletionStream is not None
assert ChatCompletion is not None
assert ChatCompletionChunk is not None
assert Choice is not None
assert ChoiceDelta is not None
assert Response is not None
def test_openai_sdk_client_instantiation():
"""
Test that OpenAI client can be instantiated with the current SDK version.
This test verifies that the OpenAI client initialization works correctly
with the installed SDK version, ensuring compatibility with newer versions.
Related to issue #4300: Dependency constraints in pyproject.toml are overly strict
"""
from openai import AsyncOpenAI, OpenAI
client = OpenAI(api_key="test-key")
async_client = AsyncOpenAI(api_key="test-key")
assert client is not None
assert async_client is not None
assert hasattr(client, "chat")
assert hasattr(client.chat, "completions")
assert hasattr(async_client, "chat")
assert hasattr(async_client.chat, "completions")

View File

@@ -1,51 +0,0 @@
"""Tests for Qdrant types module."""
import pytest
class TestQdrantTypesImport:
"""Test suite for Qdrant types module imports."""
def test_qdrant_types_import_succeeds(self):
"""Test that qdrant types module can be imported without errors.
This test verifies that the types module is compatible with the
installed version of qdrant-client, particularly ensuring that
removed/deprecated imports like InitFrom don't cause ImportError.
"""
from crewai.rag.qdrant.types import (
CommonCreateFields,
CreateCollectionParams,
EmbeddingFunction,
QdrantClientParams,
QdrantCollectionCreateParams,
)
assert CommonCreateFields is not None
assert CreateCollectionParams is not None
assert EmbeddingFunction is not None
assert QdrantClientParams is not None
assert QdrantCollectionCreateParams is not None
def test_common_create_fields_does_not_have_init_from(self):
"""Test that CommonCreateFields no longer has init_from field.
The init_from field was removed because InitFrom class was
deprecated and removed from qdrant-client.
"""
from crewai.rag.qdrant.types import CommonCreateFields
annotations = CommonCreateFields.__annotations__
assert "init_from" not in annotations
def test_qdrant_client_module_import_succeeds(self):
"""Test that the qdrant client module can be imported without errors."""
from crewai.rag.qdrant.client import QdrantClient
assert QdrantClient is not None
def test_qdrant_utils_module_import_succeeds(self):
"""Test that the qdrant utils module can be imported without errors."""
from crewai.rag.qdrant.utils import _get_collection_params
assert _get_collection_params is not None