Skip to content

Commit 6c0d9ec

Browse files
authored
chore: enable LiteLLM on Python 3.14 (#14170)
* chore: enable LiteLLM on Python 3.14 * test: clarify optional dependency availability
1 parent 1957085 commit 6c0d9ec

17 files changed

Lines changed: 186 additions & 358 deletions

pyproject.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,8 @@ override-dependencies = [
223223
"dynaconf>=3.2.13",
224224
"pillow>=12.1.1", # Force Pillow 12.1.1+ to prevent CVE-vulnerable versions
225225
"playwright>=1.59.0", # Latest available on PyPI; ensures updated Chromium with CVE fixes
226-
# Keep uv workspace resolution on the supported LiteLLM floor without forcing
227-
# an upstream package that declares Requires-Python <3.14 onto Python 3.14.
228-
"litellm>=1.85.1,<2.0.0; python_version < '3.14'",
226+
# Keep uv workspace resolution on the Python 3.14-compatible LiteLLM floor.
227+
"litellm>=1.93.0,<2.0.0",
229228
# Transitive dependency CVE fixes
230229
"lxml>=6.1.0,<7.0.0", # CVE-2026-41066
231230
"mako>=1.3.12,<2.0.0", # CVE-2026-44307

scripts/ci/test_update_lf_base_dependency.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def pyproject(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
3131
"\n"
3232
"[project.optional-dependencies]\n"
3333
'cassandra = ["lfx[cassandra]~=1.11.0"]\n'
34-
"toolguard = [\"lfx[toolguard]~=1.11.0; python_version < '3.14'\"]\n"
34+
"toolguard = [\"lfx[toolguard]~=1.11.0; sys_platform != 'win32'\"]\n"
3535
'beautifulsoup = ["lfx~=1.11.0"]\n'
3636
)
3737
path = tmp_path / "pyproject.toml"
@@ -48,7 +48,7 @@ def test_pins_bare_and_extras_lfx_to_exact_dev(pyproject: Path) -> None:
4848
# Every lfx reference -- bare and with extras -- is pinned to the exact dev version.
4949
assert '"lfx==1.11.0.dev26"' in result
5050
assert '"lfx[cassandra]==1.11.0.dev26"' in result
51-
assert "\"lfx[toolguard]==1.11.0.dev26; python_version < '3.14'\"" in result
51+
assert "\"lfx[toolguard]==1.11.0.dev26; sys_platform != 'win32'\"" in result
5252

5353
# No `~=` floor survives -- a surviving floor is exactly what makes the nightly
5454
# resolve unsatisfiable.

scripts/ci/test_update_lfx_pre_release_dependency.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ def test_preserves_lfx_extras_and_markers():
55
content = """
66
dependencies = ["lfx~=1.11.0"]
77
cassandra = ["lfx[cassandra]~=1.11.0"]
8-
toolguard = ["lfx[toolguard]>=1.11.0; python_version < '3.14'"]
8+
toolguard = ["lfx[toolguard]>=1.11.0; sys_platform != 'win32'"]
99
provider = ["lfx-openai>=0.1.0,<1.0.0"]
1010
"""
1111

1212
result = update_lfx_requirements(content, "1.11.0rc2")
1313

1414
assert '"lfx>=1.11.0rc2,<1.12.dev0"' in result
1515
assert '"lfx[cassandra]>=1.11.0rc2,<1.12.dev0"' in result
16-
assert "\"lfx[toolguard]>=1.11.0rc2,<1.12.dev0; python_version < '3.14'\"" in result
16+
assert "\"lfx[toolguard]>=1.11.0rc2,<1.12.dev0; sys_platform != 'win32'\"" in result
1717
assert '"lfx-openai>=0.1.0,<1.0.0"' in result
1818

1919

scripts/ci/update_lf_base_dependency.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def update_lfx_dep_in_base(pyproject_path: str, lfx_version: str) -> None:
4646

4747
# Updated pattern to handle PEP 440 version suffixes, both ~= and == version specifiers,
4848
# both lfx and lfx-nightly names, extras (e.g. lfx[cassandra], lfx[toolguard]), and
49-
# trailing markers (e.g. `; python_version < '3.14'`).
49+
# trailing markers (e.g. `; sys_platform != 'win32'`).
5050
# The extras group (1) MUST be preserved: base's `[complete]` extra pulls these
5151
# `lfx[extra]` references, and if they keep a `~=X.Y.0` floor while base's bare `lfx`
5252
# dep is pinned to `==X.Y.0.devN`, the floor (>=X.Y.0) excludes the dev release and

scripts/migrate/consolidate_bundles.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,8 @@
142142
"google-auth-oauthlib>=1.2.0,<2.0.0",
143143
],
144144
"vertexai": ["langchain-google-vertexai>=3.2.0"],
145-
# ALTK depends on litellm, whose current Rust extension does not build on Python 3.14.
146145
"altk": [
147-
"agent-lifecycle-toolkit>=0.10.1,<1.0; "
148-
"(sys_platform != 'darwin' or platform_machine != 'x86_64') and python_version < '3.14'",
146+
"agent-lifecycle-toolkit>=0.10.1,<1.0; sys_platform != 'darwin' or platform_machine != 'x86_64'",
149147
],
150148
"codeagents": [
151149
"smolagents>=1.8.0",

src/backend/base/pyproject.toml

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -304,12 +304,7 @@ numexpr = ["numexpr>=2.10.2"]
304304
qianfan = ["qianfan==0.3.5"]
305305
pgvector = ["pgvector>=0.4.2"]
306306
litellm = [
307-
# litellm has no Python 3.14-compatible release: every version from 1.83.8
308-
# onward declares Requires-Python <3.14, so nothing satisfying our >=1.85.1
309-
# floor installs on 3.14 (the newest 3.14-installable litellm is 1.83.7).
310-
# Gate it off on 3.14 so `pip install langflow` resolves there instead of
311-
# dead-ending; drop the marker once upstream ships a 3.14-compatible litellm.
312-
"litellm>=1.85.1,<2.0.0; python_version < '3.14'",
307+
"litellm>=1.93.0,<2.0.0",
313308
# Runtime deps from litellm[proxy] that langflow-ide hits when logging
314309
# to langfuse via litellm.proxy.proxy_server (issue #12228). The full
315310
# Pull in only the modules Langflow uses from litellm[proxy] rather than
@@ -343,17 +338,10 @@ spider = ["spider-client>=0.0.27,<1.0.0"]
343338
# Updated to 0.10.1+ for PyTorch 2.6.0 compatibility (addresses torch.load RCE vulnerability)
344339
# Upper bound prevents breaking changes in future major versions
345340
# Excluded on macOS x86_64: PyTorch dropped Intel Mac wheel builds after v2.2.2
346-
# Python 3.14: re-gated off 3.14. altk 0.10.x itself supports 3.14 (requires-python
347-
# >=3.10) and no longer depends on OpenDsStar, but it depends on litellm<2.0.0, and
348-
# litellm has no 3.14-compatible release (every version from 1.83.8 on caps at <3.14,
349-
# see the litellm extra below). Without this gate the resolver pins an uninstallable
350-
# litellm on 3.14. Re-enable once upstream litellm supports 3.14.
351-
altk = ["agent-lifecycle-toolkit>=0.10.1,<1.0; (sys_platform != 'darwin' or platform_machine != 'x86_64') and python_version < '3.14'"]
341+
altk = ["agent-lifecycle-toolkit>=0.10.1,<1.0; sys_platform != 'darwin' or platform_machine != 'x86_64'"]
352342

353343
# Toolguard Integration
354-
# Gated off 3.14: lfx[toolguard] pulls the ToolGuard Policies component, which
355-
# depends on litellm. Re-enable once upstream litellm supports 3.14.
356-
toolguard = ["lfx[toolguard]~=1.11.0; python_version < '3.14'"] # toolguard relocated to lfx
344+
toolguard = ["lfx[toolguard]~=1.11.0"] # toolguard relocated to lfx
357345

358346
# Additional LangChain integrations
359347
# Excluded on macOS x86_64: transitive torch dependency (via sentence-transformers) has no Intel Mac wheels
@@ -364,11 +352,7 @@ langchain-unstructured = ["langchain-unstructured~=1.0.0"]
364352
langchain-mcp-adapters = ["langchain-mcp-adapters>=0.1.14,<0.2.0"]
365353

366354
# Additional monitoring
367-
# Gated off 3.14: opik depends on litellm unconditionally, and litellm has no
368-
# 3.14-compatible release (see the litellm extra above), so allowing it on 3.14
369-
# would drag in an uninstallable / sub-floor litellm. Re-enable once upstream
370-
# litellm supports 3.14.
371-
opik = ["opik>=2.0.0,<3.0.0; python_version < '3.14'"]
355+
opik = ["opik>=2.0.0,<3.0.0"]
372356
traceloop = ["traceloop-sdk>=0.43.1,<1.0.0"]
373357
openlayer = ["openlayer>=0.9.0,<1.0.0"]
374358

src/backend/tests/unit/components/models_and_agents/policies/test_guarded_tool.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
from unittest.mock import AsyncMock, MagicMock
22

33
import pytest
4-
5-
try:
6-
import toolguard # noqa: F401
7-
except ImportError:
8-
# toolguard is an optional extra (langflow-base[toolguard]); skip if not
9-
# installed. Gated off Python 3.14 because it depends on litellm, which has
10-
# no 3.14-compatible release (see langflow-base pyproject).
11-
pytest.skip("toolguard not available", allow_module_level=True)
12-
134
from langchain_core.tools import StructuredTool
145
from lfx.components.models_and_agents.policies.guarded_tool import GuardedTool
156
from pydantic import BaseModel

src/backend/tests/unit/components/models_and_agents/policies/test_llm_wrapper.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
from unittest.mock import AsyncMock, MagicMock
22

33
import pytest
4-
5-
try:
6-
import toolguard # noqa: F401
7-
except ImportError:
8-
# toolguard is an optional extra (langflow-base[toolguard]); skip if not
9-
# installed. Gated off Python 3.14 because it depends on litellm, which has
10-
# no 3.14-compatible release (see langflow-base pyproject). The component
11-
# imported below pulls in toolguard at module load.
12-
pytest.skip("toolguard not available", allow_module_level=True)
13-
144
from langchain_core.messages import AIMessage
155
from langchain_core.outputs import ChatGeneration, LLMResult
166
from lfx.components.models_and_agents.policies.llm_wrapper import LangchainModelWrapper

src/backend/tests/unit/components/models_and_agents/policies/test_tool_invoker.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
from unittest.mock import AsyncMock, MagicMock
22

33
import pytest
4-
5-
try:
6-
import toolguard # noqa: F401
7-
except ImportError:
8-
# toolguard is an optional extra (langflow-base[toolguard]); skip if not
9-
# installed. Gated off Python 3.14 because it depends on litellm, which has
10-
# no 3.14-compatible release (see langflow-base pyproject). The component
11-
# imported below pulls in toolguard at module load.
12-
pytest.skip("toolguard not available", allow_module_level=True)
13-
144
from lfx.components.models_and_agents.policies.tool_invoker import ToolInvoker
155
from mcp.types import CallToolResult
166
from pydantic import BaseModel

src/backend/tests/unit/components/test_all_modules_importable.py

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -68,22 +68,6 @@ def test_all_component_categories_importable(self):
6868

6969
def test_all_components_in_categories_importable(self):
7070
"""Test that all components in each category's __all__ can be imported."""
71-
import sys
72-
73-
# Components whose underlying packages are gated to python_version<'3.14'
74-
# in pyproject.toml because upstream pins exclude 3.14. These are expected
75-
# to fail import on 3.14 until the upstreams adapt.
76-
# NOTE: ibm.* moved to the lfx-ibm bundle (src/bundles/ibm) and is no
77-
# longer iterated through ``langflow.components``; the watsonx
78-
# 3.14-gating moved with them.
79-
gated_on_py314 = {
80-
"altk.ALTKAgentComponent",
81-
"crewai.CrewAIAgentComponent",
82-
"crewai.HierarchicalCrewComponent",
83-
"crewai.SequentialCrewComponent",
84-
}
85-
on_py314 = sys.version_info >= (3, 14)
86-
8771
failed_imports = []
8872
successful_imports = 0
8973

@@ -108,9 +92,6 @@ def test_all_components_in_categories_importable(self):
10892
successful_imports += 1
10993

11094
except Exception as e:
111-
if on_py314 and qualified in gated_on_py314:
112-
print(f"SKIPPED on 3.14: {qualified}: {e!s}") # noqa: T201
113-
continue
11495
failed_imports.append(f"{qualified}: {e!s}")
11596
print(f"FAILED: {qualified}: {e!s}") # noqa: T201
11697
else:
@@ -448,8 +429,7 @@ async def import_module_async(modname):
448429
"redis",
449430
"elasticsearch",
450431
"langchain_community",
451-
# Gated to python_version<'3.14' in pyproject.toml until
452-
# upstream caps lift.
432+
# ALTK is excluded on Intel macOS; the IBM integrations remain optional.
453433
"altk",
454434
"langchain_ibm",
455435
"ibm_watsonx_ai",
@@ -458,12 +438,6 @@ async def import_module_async(modname):
458438
"lfx-openai",
459439
"lfx-datastax",
460440
"lfx-oracle",
461-
# litellm has no 3.14-compatible release, so it is gated to
462-
# python_version<'3.14'. Its absence surfaces transitively
463-
# via crewai (``from crewai import Agent`` -> litellm) and
464-
# via toolguard (the policies components import it directly).
465-
"litellm",
466-
"toolguard",
467441
]
468442
):
469443
return ("skipped", modname, "missing optional dependency")

0 commit comments

Comments
 (0)