chore: security patch (#12725)

* chore: security patch

security patch

* chore: upgrade package-lock.json

* chore: smolagents and transformer update

* chore: redis upgrade

* chore: litellm upgrade

* fix: Pin click to avoid lower versions

## Root cause

**litellm 1.83.5+** introduced an exact pin `click==8.1.8` in its `requires_dist` (upstream bug [BerriAI/litellm#26154](https://github.com/BerriAI/litellm/issues/26154) — "Pinning exact dependency versions breaks downstream consumers"). When this branch bumped litellm to 1.83.11, uv was forced to downgrade click from 8.3.2 → 8.1.8. Click 8.2+ captures stderr separately by default; 8.1 merges it — hence `ValueError: stderr not separately captured`.

## Fix

- [pyproject.toml:155](pyproject.toml:155) — added `"click>=8.3.0"` to `[tool.uv] override-dependencies` with comment linking the upstream issue.
- [src/backend/base/pyproject.toml:112](src/backend/base/pyproject.toml:112) — same override so `langflow-base` Docker builds pick it up too.
- Regenerated `uv.lock` (click: 8.1.8 → 8.3.3).
- Patched the `click` entry in `src/backend/base/uv.lock` to 8.3.3 (that lockfile is used by `docker/build_and_push_base.Dockerfile` via `uv sync --frozen`; uv treats backend/base as a workspace member so I updated its click block directly — no other references to 8.1.8 remain).
- Reverted [src/lfx/tests/unit/cli/test_run_real_flows.py](src/lfx/tests/unit/cli/test_run_real_flows.py) back to its original `result.stderr` usage — now passes cleanly with click 8.3.3.

All 19 tests in the file pass.

* Update build_and_push_backend.Dockerfile

The `uv pip install` command doesn't read `[tool.uv] override-dependencies` from the target packages' pyproject.toml — those overrides only apply during `uv lock`/`uv sync`. The fix is to pass the overrides explicitly via `--overrides`.

Now let me verify it works by running the same install locally.

Resolution succeeded — click==8.3.3, aiohttp==3.13.5, litellm==1.83.11 all coexist. Let me also test without `--overrides` to confirm I reproduce the original failure.

Reproduced the Docker failure locally. Now test with the overrides file:

Fix verified — resolution succeeds with the overrides file, failing without. Let me clean up and show the final Dockerfile change.

## Summary

**Root cause:** The Dockerfile uses `uv pip install ./src/...` which **does not read** `[tool.uv] override-dependencies` from the target packages' `pyproject.toml` — those overrides only apply during `uv lock`/`uv sync`. On Linux, `cuga>=0.2.20` requires `aiohttp>=3.13.5`, but `litellm==1.83.11` exact-pins `aiohttp==3.13.3` (same upstream bug as the click pin, [BerriAI/litellm#26154](https://github.com/BerriAI/litellm/issues/26154)). Without an active override, resolution fails.

**Fix:** Write a `/tmp/uv-overrides.txt` file mirroring the workspace's `override-dependencies` (litellm, python-dotenv, openai, aiohttp, click) and pass `--overrides /tmp/uv-overrides.txt` to `uv pip install`.

Verified locally by reproducing the exact failure in an isolated tmp directory (to escape the workspace's pyproject.toml auto-apply), then confirming the overrides file resolves it:
- aiohttp==3.13.5 ✓
- click==8.3.3 ✓
- litellm==1.83.11 ✓
- cuga==0.2.22 ✓

* Templates version update

* Update .secrets.baseline

* chore: update overrides

* chore: bump version

* chore: bump main version

* chore: bump SDK version to 0.1.1

* chore: run uv lock and uv sync after SDK version bump

* chore: read the overrides from a single source

security patch

* chore: add pip check toggle

add pip check toggle

* chore: litellm base uv.lock update

* fix(chore): Pin litellm back to last working release

* fix(chore): Pin to 1.83 and higher litellm

* Update build_and_push_backend.Dockerfile

* chore: update base uv.lock

* fix: lazyload toolguard since its an optional extra

* Update .secrets.baseline

* Update component_index.json

* Rebuild component index

* Update component_index.json

---------

Co-authored-by: Eric Hare <[email protected]>
Co-authored-by: vijay kumar katuri <[email protected]>
(cherry picked from commit 60a8f76c3fde17124057626c671ea8162872837a)
This commit is contained in:
Adam-Aghili
2026-04-23 17:49:53 -07:00
committed by Eric Hare
parent 3d0155e1cc
commit 26b19cba5e
53 changed files with 2755 additions and 2136 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ description: Write and review Playwright E2E tests for Langflow. Trigger when th
| Tool | Version | Purpose |
|------|---------|---------|
| Playwright | 1.57.0 | E2E test runner + browser automation |
| Playwright | 1.59.1 | E2E test runner + browser automation |
| Chromium | (bundled) | Default browser (Firefox/Safari disabled) |
| Custom fixtures | `tests/fixtures.ts` | Auto-detects API errors and flow execution failures |
+12 -4
View File
@@ -53,6 +53,11 @@ on:
required: false
type: boolean
default: true
run_pip_check:
description: "Whether to run pip check - ONLY SET TO FALSE ONCE YOU HAVE ALREADY ATTEMPTED AND FAILED A RUN THEN MADE SURE DEPS DO NOT CAUSE FAILURES"
required: false
type: boolean
default: true
jobs:
echo-inputs:
@@ -107,7 +112,7 @@ jobs:
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Validate Tag Has v Prefix
run: |
TAG="${{ inputs.release_tag }}"
@@ -119,12 +124,12 @@ jobs:
exit 1
fi
echo "✅ Tag format is valid: $TAG"
- name: Check for Duplicate Tag Without v Prefix
run: |
TAG="${{ inputs.release_tag }}"
TAG_WITHOUT_V="${TAG#v}"
if git rev-parse "$TAG_WITHOUT_V" >/dev/null 2>&1; then
echo "❌ Error: Duplicate tag without 'v' prefix exists: $TAG_WITHOUT_V"
echo " This will cause release notes to use the wrong base comparison."
@@ -600,6 +605,7 @@ jobs:
fi
uv pip install $FIND_LINKS --prerelease=allow -e src/backend/base
- name: Check for dependency incompatibility
if: ${{ inputs.run_pip_check }}
run: uv pip check
- name: Set version for pre-release
if: ${{ inputs.pre_release }}
@@ -747,6 +753,7 @@ jobs:
fi
uv pip install $FIND_LINKS --prerelease=allow -e .
- name: Check for dependency incompatibility
if: ${{ inputs.run_pip_check }}
run: uv pip check
- name: Set version for pre-release
if: ${{ inputs.pre_release }}
@@ -1040,7 +1047,8 @@ jobs:
create_release:
name: Create Release
runs-on: ubuntu-latest
needs: [determine-main-version, build-main, publish-main, validate-tag-format]
needs:
[determine-main-version, build-main, publish-main, validate-tag-format]
if: |
always() &&
!cancelled() &&
+1 -1
View File
@@ -70,7 +70,7 @@ env:
# Define the directory where Playwright browsers will be installed.
# This path is used for caching across workflows
PLAYWRIGHT_BROWSERS_PATH: "ms-playwright"
PLAYWRIGHT_VERSION: "1.57.0"
PLAYWRIGHT_VERSION: "1.59.1"
LANGFLOW_FEATURE_WXO_DEPLOYMENTS: "true"
jobs:
+3 -131
View File
@@ -197,7 +197,7 @@
"filename": ".github/workflows/release.yml",
"hashed_secret": "3e26d6750975d678acb8fa35a0f69237881576b0",
"is_verified": false,
"line_number": 346,
"line_number": 391,
"is_secret": false
}
],
@@ -1726,38 +1726,6 @@
"hashed_secret": "d6e6d7b4b115cd3b9d172623199f8c403055fecc",
"is_verified": false,
"line_number": 659
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json",
"hashed_secret": "665b1e3851eefefa3fb878654292f16597d25155",
"is_verified": false,
"line_number": 1506,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json",
"hashed_secret": "3f2df46921dd8e2c36e2ce85238705ac0774c74a",
"is_verified": false,
"line_number": 1641,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json",
"hashed_secret": "d3d6fe3f7d33d0f4aa28c49544a865982a48a00a",
"is_verified": false,
"line_number": 1701,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json",
"hashed_secret": "d4c3d66fd0c38547a3c7a4c6bdc29c36911bc030",
"is_verified": false,
"line_number": 1766,
"is_secret": false
}
],
"src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json": [
@@ -2259,44 +2227,12 @@
"line_number": 1612,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json",
"hashed_secret": "665b1e3851eefefa3fb878654292f16597d25155",
"is_verified": false,
"line_number": 1803,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json",
"hashed_secret": "3f2df46921dd8e2c36e2ce85238705ac0774c74a",
"is_verified": false,
"line_number": 1938,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json",
"hashed_secret": "d3d6fe3f7d33d0f4aa28c49544a865982a48a00a",
"is_verified": false,
"line_number": 1998,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json",
"hashed_secret": "d4c3d66fd0c38547a3c7a4c6bdc29c36911bc030",
"is_verified": false,
"line_number": 2063,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json",
"hashed_secret": "13f728be4fd927580a98667bcd624f511f459de0",
"is_verified": false,
"line_number": 2333
"line_number": 2017
}
],
"src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json": [
@@ -2449,38 +2385,6 @@
"hashed_secret": "d6e6d7b4b115cd3b9d172623199f8c403055fecc",
"is_verified": false,
"line_number": 650
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json",
"hashed_secret": "665b1e3851eefefa3fb878654292f16597d25155",
"is_verified": false,
"line_number": 1278,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json",
"hashed_secret": "3f2df46921dd8e2c36e2ce85238705ac0774c74a",
"is_verified": false,
"line_number": 1410,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json",
"hashed_secret": "d3d6fe3f7d33d0f4aa28c49544a865982a48a00a",
"is_verified": false,
"line_number": 1470,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json",
"hashed_secret": "d4c3d66fd0c38547a3c7a4c6bdc29c36911bc030",
"is_verified": false,
"line_number": 1535,
"is_secret": false
}
],
"src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json": [
@@ -2523,38 +2427,6 @@
"is_verified": false,
"line_number": 1480,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json",
"hashed_secret": "665b1e3851eefefa3fb878654292f16597d25155",
"is_verified": false,
"line_number": 1671,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json",
"hashed_secret": "3f2df46921dd8e2c36e2ce85238705ac0774c74a",
"is_verified": false,
"line_number": 1806,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json",
"hashed_secret": "d3d6fe3f7d33d0f4aa28c49544a865982a48a00a",
"is_verified": false,
"line_number": 1866,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json",
"hashed_secret": "d4c3d66fd0c38547a3c7a4c6bdc29c36911bc030",
"is_verified": false,
"line_number": 1931,
"is_secret": false
}
],
"src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json": [
@@ -8373,5 +8245,5 @@
}
]
},
"generated_at": "2026-04-14T23:44:15Z"
"generated_at": "2026-04-23T21:12:19Z"
}
+12
View File
@@ -0,0 +1,12 @@
{
"settingsInheritedFrom": "whitesource-config/whitesource-config@master",
"scanSettings": {
"dependencyScopes": [
"prod"
],
"baseBranches": [
"main",
"release-*"
]
}
}
-2
View File
@@ -99,8 +99,6 @@ RUN useradd user -u 1000 -g 0 --no-create-home --home-dir /app/data
COPY --from=builder --chown=1000 /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
RUN /app/.venv/bin/pip install --upgrade playwright \
&& /app/.venv/bin/playwright install
LABEL org.opencontainers.image.title=langflow
LABEL org.opencontainers.image.authors=['Langflow']
+1
View File
@@ -37,6 +37,7 @@ RUN uv venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
ENV VIRTUAL_ENV="/app/.venv"
# Install langflow-base with all extras except dev (which includes Playwright)
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install ./src/sdk ./src/lfx "./src/backend/base[complete,postgresql]"
-2
View File
@@ -101,8 +101,6 @@ RUN useradd user -u 1000 -g 0 --no-create-home --home-dir /app/data
COPY --from=builder --chown=1000 /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
RUN /app/.venv/bin/pip install --upgrade playwright \
&& /app/.venv/bin/playwright install
LABEL org.opencontainers.image.title=langflow
LABEL org.opencontainers.image.authors=['Langflow']
-2
View File
@@ -95,8 +95,6 @@ RUN useradd user -u 1000 -g 0 --no-create-home --home-dir /app/data
COPY --from=builder --chown=1000 /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
RUN /app/.venv/bin/pip install --upgrade playwright \
&& /app/.venv/bin/playwright install
LABEL org.opencontainers.image.title=langflow
LABEL org.opencontainers.image.authors=['Langflow']
@@ -96,8 +96,6 @@ RUN useradd user -u 1000 -g 0 --no-create-home --home-dir /app/data
COPY --from=builder --chown=1000 /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
RUN /app/.venv/bin/pip install --upgrade playwright \
&& /app/.venv/bin/playwright install
LABEL org.opencontainers.image.title=langflow
LABEL org.opencontainers.image.authors=['Langflow']
+2 -4
View File
@@ -1,6 +1,6 @@
[project]
name = "langflow"
version = "1.9.0"
version = "1.9.1"
description = "A Python package with a built-in web application"
requires-python = ">=3.10,<3.14"
license = "MIT"
@@ -17,7 +17,7 @@ maintainers = [
]
# Define your main dependencies here
dependencies = [
"langflow-base[complete]>=0.9.0",
"langflow-base[complete]>=0.9.1",
]
@@ -146,8 +146,6 @@ override-dependencies = [
"Markdown>=3.8.0",
"dynaconf>=3.2.13",
"pillow>=12.1.1", # Force Pillow 12.1.1+ to prevent CVE-vulnerable versions
"aiohttp>=3.13.4",
"litellm>=1.83.0",
"playwright>=1.58.0", # Latest available on PyPI; ensures updated Chromium with CVE fixes
]
@@ -665,7 +665,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -2478,4 +2478,4 @@
"tags": [
"chatbots"
]
}
}
@@ -626,7 +626,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1264,4 +1264,4 @@
"tags": [
"chatbots"
]
}
}
@@ -542,7 +542,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1792,4 +1792,4 @@
"chatbots",
"content-generation"
]
}
}
@@ -2400,7 +2400,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -3040,4 +3040,4 @@
"coding",
"web-scraping"
]
}
}
@@ -420,7 +420,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1319,7 +1319,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
},
{
"name": "pydantic",
@@ -134,7 +134,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1259,4 +1259,4 @@
"chatbots",
"content-generation"
]
}
}
@@ -678,7 +678,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1521,7 +1521,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
},
{
"name": "lfx",
@@ -460,7 +460,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1814,4 +1814,4 @@
"tags": [
"classification"
]
}
}
@@ -1128,7 +1128,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -2084,7 +2084,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -346,7 +346,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1192,7 +1192,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -263,7 +263,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -541,7 +541,7 @@
"dependencies": [
{
"name": "chromadb",
"version": "1.5.7"
"version": "1.5.8"
},
{
"name": "cryptography",
@@ -565,15 +565,15 @@
},
{
"name": "langchain_openai",
"version": "1.1.12"
"version": "1.2.0"
},
{
"name": "langchain_huggingface",
"version": "1.2.1"
"version": "1.2.2"
},
{
"name": "langchain_cohere",
"version": "0.5.0"
"version": "0.5.1"
},
{
"name": "langchain_google_genai",
@@ -456,7 +456,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1204,7 +1204,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -689,7 +689,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -969,7 +969,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1249,7 +1249,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -2514,7 +2514,7 @@
}
],
"pinned": false,
"score": 1.8578044550916993e-05,
"score": 0.000018578044550916993,
"template": {
"_type": "Component",
"api_key": {
@@ -3783,4 +3783,4 @@
"chatbots",
"content-generation"
]
}
}
@@ -429,7 +429,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1661,4 +1661,4 @@
"openai",
"assistants"
]
}
}
@@ -890,7 +890,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1186,7 +1186,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -1765,7 +1765,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -517,7 +517,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -813,7 +813,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -2105,7 +2105,7 @@
"dependencies": [
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
},
{
"name": "pydantic",
@@ -400,7 +400,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1251,7 +1251,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -332,7 +332,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -941,7 +941,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
},
{
"name": "pydantic",
@@ -424,7 +424,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1620,7 +1620,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -1772,7 +1772,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -2823,7 +2823,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -376,7 +376,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -632,7 +632,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1293,4 +1293,4 @@
"chatbots",
"assistants"
]
}
}
@@ -409,7 +409,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -905,7 +905,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -115,7 +115,7 @@
},
{
"name": "scrapegraph_py",
"version": "1.46.0"
"version": "2.1.0"
}
],
"total_dependencies": 2
@@ -575,7 +575,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -952,7 +952,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -370,7 +370,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -958,7 +958,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -2403,7 +2403,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -2976,7 +2976,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
},
{
"name": "pydantic",
@@ -3795,7 +3795,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -656,7 +656,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -951,7 +951,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -160,7 +160,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
},
{
"name": "pydantic",
@@ -392,7 +392,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
},
{
"name": "pydantic",
@@ -980,7 +980,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1301,7 +1301,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -830,7 +830,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1112,7 +1112,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -2633,7 +2633,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
},
{
"name": "pydantic",
@@ -507,7 +507,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1717,7 +1717,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -2300,7 +2300,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -2883,7 +2883,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -710,7 +710,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -2377,4 +2377,4 @@
"chatbots",
"content-generation"
]
}
}
@@ -754,7 +754,7 @@
"dependencies": [
{
"name": "langchain_text_splitters",
"version": "1.1.1"
"version": "1.1.2"
},
{
"name": "lfx",
@@ -1079,7 +1079,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
@@ -1635,7 +1635,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
},
{
"name": "pydantic",
@@ -2707,7 +2707,7 @@
},
{
"name": "chromadb",
"version": "1.5.7"
"version": "1.5.8"
}
],
"total_dependencies": 7
@@ -3053,7 +3053,7 @@
"dependencies": [
{
"name": "chromadb",
"version": "1.5.7"
"version": "1.5.8"
},
{
"name": "cryptography",
@@ -3077,15 +3077,15 @@
},
{
"name": "langchain_openai",
"version": "1.1.12"
"version": "1.2.0"
},
{
"name": "langchain_huggingface",
"version": "1.2.1"
"version": "1.2.2"
},
{
"name": "langchain_cohere",
"version": "0.5.0"
"version": "0.5.1"
},
{
"name": "langchain_google_genai",
@@ -513,7 +513,7 @@
},
{
"name": "langchain_core",
"version": "1.2.29"
"version": "1.3.1"
}
],
"total_dependencies": 3
@@ -1297,7 +1297,7 @@
},
{
"name": "fastapi",
"version": "0.135.3"
"version": "0.136.1"
},
{
"name": "lfx",
+6 -10
View File
@@ -1,6 +1,6 @@
[project]
name = "langflow-base"
version = "0.9.0"
version = "0.9.1"
description = "A Python package with a built-in web application"
requires-python = ">=3.10,<3.14"
license = "MIT"
@@ -17,7 +17,7 @@ maintainers = [
]
dependencies = [
"lfx~=0.4.0",
"lfx~=0.4.1",
"fastapi>=0.135.0,<1.0.0",
"httpx[http2]>=0.27,<1.0.0",
"aiofile>=3.9.0,<4.0.0",
@@ -100,11 +100,7 @@ dependencies = [
"dynaconf>=3.2.13,<4.0.0",
"pyasn1>=0.6.3,<0.7.0",
"langgraph-checkpoint>4.0.0,<5.0.0",
]
[tool.uv]
override-dependencies = [
"litellm>=1.83.0"
"transformers>=5.6.0,<6.0.0",
]
[dependency-groups]
@@ -193,7 +189,7 @@ clickhouse = ["clickhouse-connect==0.7.19"]
mongodb = ["pymongo==4.10.1"]
supabase = ["supabase>=2.6.0,<3.0.0"]
redis = ["redis>=5.2.1,<6.0.0"]
redis = ["redis>=7.4.0,<8.0.0"]
elasticsearch = ["elasticsearch~=8.19", "langchain-elasticsearch~=1.0.0"]
# Individual vector store providers
@@ -270,7 +266,7 @@ nltk = ["nltk>=3.9.4"]
lark = ["lark==1.2.2"]
# Additional dependencies from requirements
huggingface = ["huggingface-hub[inference]>=0.23.2,<1.0.0"]
huggingface = ["huggingface-hub[inference]>=1.0.0,<2.0.0"]
metaphor = ["metaphor-python==0.1.23"]
metal = ["metal_sdk==2.5.1"]
markup = ["MarkupSafe==3.0.2"]
@@ -278,7 +274,7 @@ aws = ["boto3>=1.34.162,<2.0.0", "langchain-aws~=1.1.0"]
numexpr = ["numexpr==2.10.2"]
qianfan = ["qianfan==0.3.5"]
pgvector = ["pgvector>=0.4.2"]
litellm = ["litellm>=1.83.0,<2.0.0"]
litellm = ["litellm>=1.83.0"]
zep = ["zep-python==2.0.2"]
youtube = ["youtube-transcript-api>=1.0.0,<2.0.0"]
markdown = ["Markdown>=3.8.0"]
+1229 -660
View File
File diff suppressed because it is too large Load Diff
@@ -59,6 +59,7 @@ payloads_module = importlib.import_module("langflow.services.adapters.deployment
client_module = importlib.import_module("langflow.services.adapters.deployment.watsonx_orchestrate.client")
types_module = importlib.import_module("langflow.services.adapters.deployment.watsonx_orchestrate.types")
deployment_context_module = importlib.import_module("langflow.services.adapters.deployment.context")
utils_module = importlib.import_module("langflow.services.adapters.deployment.watsonx_orchestrate.utils")
WatsonxOrchestrateDeploymentService = importlib.import_module(
"langflow.services.adapters.deployment.watsonx_orchestrate"
).WatsonxOrchestrateDeploymentService
@@ -78,6 +79,10 @@ ListConfigsResponse = importlib.import_module(
TEST_WXO_LLM = "ibm/granite-3.3-8b"
def _normalized_provider_app_id(app_id: str) -> str:
return utils_module.validate_wxo_name(app_id)
def _reload_wxo_auth_modules():
constants_module = importlib.import_module("langflow.services.adapters.deployment.watsonx_orchestrate.constants")
importlib.reload(constants_module)
@@ -1780,8 +1785,10 @@ async def test_apply_provider_create_plan_rolls_back_successfully_created_raw_co
error_prefix,
created_app_ids_journal=None,
):
_ = clients, payload, user_id, db, error_prefix, created_app_ids_journal
if app_id.endswith("cfg-a"):
_ = clients, payload, user_id, db, error_prefix
if app_id == _normalized_provider_app_id("cfg-a"):
if created_app_ids_journal is not None:
created_app_ids_journal.append(app_id)
return app_id
msg = "boom-create-connection"
raise RuntimeError(msg)
@@ -1809,7 +1816,7 @@ async def test_apply_provider_create_plan_rolls_back_successfully_created_raw_co
plan=plan,
)
assert captured.get("rollback_app_ids") == ["cfg-a"]
assert captured.get("rollback_app_ids") == [_normalized_provider_app_id("cfg-a")]
@pytest.mark.anyio
@@ -1853,10 +1860,12 @@ async def test_apply_provider_create_plan_rolls_back_all_journaled_raw_connectio
error_prefix,
created_app_ids_journal=None,
):
_ = clients, payload, user_id, db, error_prefix, created_app_ids_journal
if app_id.endswith("cfg-c"):
_ = clients, payload, user_id, db, error_prefix
if app_id == _normalized_provider_app_id("cfg-c"):
msg = "boom-create-connection"
raise RuntimeError(msg)
if created_app_ids_journal is not None:
created_app_ids_journal.append(app_id)
return app_id
async def mock_rollback_created_resources(*, clients, agent_id, tool_ids, app_ids=None): # noqa: ARG001
@@ -1882,7 +1891,10 @@ async def test_apply_provider_create_plan_rolls_back_all_journaled_raw_connectio
plan=plan,
)
assert captured["rollback_app_ids"] == ["cfg-a", "cfg-b"]
assert captured["rollback_app_ids"] == [
_normalized_provider_app_id("cfg-a"),
_normalized_provider_app_id("cfg-b"),
]
@pytest.mark.anyio
@@ -1953,7 +1965,7 @@ async def test_apply_provider_create_plan_rolls_back_journaled_app_ids_when_crea
plan=plan,
)
assert captured["rollback_app_ids"] == ["cfg-a"]
assert captured["rollback_app_ids"] == [_normalized_provider_app_id("cfg-a")]
@pytest.mark.anyio
@@ -2000,8 +2012,10 @@ async def test_apply_provider_update_plan_rolls_back_successfully_created_raw_co
error_prefix,
created_app_ids_journal=None,
):
_ = clients, payload, user_id, db, error_prefix, created_app_ids_journal
if app_id.endswith("cfg-a"):
_ = clients, payload, user_id, db, error_prefix
if app_id == _normalized_provider_app_id("cfg-a"):
if created_app_ids_journal is not None:
created_app_ids_journal.append(app_id)
return app_id
msg = "boom-update-connection"
raise RuntimeError(msg)
@@ -2031,7 +2045,7 @@ async def test_apply_provider_update_plan_rolls_back_successfully_created_raw_co
plan=plan,
)
assert captured["rolled_back_app_ids"] == ["cfg-a"]
assert captured["rolled_back_app_ids"] == [_normalized_provider_app_id("cfg-a")]
@pytest.mark.anyio
@@ -2079,10 +2093,12 @@ async def test_apply_provider_update_plan_rolls_back_all_journaled_raw_connectio
error_prefix,
created_app_ids_journal=None,
):
_ = clients, payload, user_id, db, error_prefix, created_app_ids_journal
if app_id.endswith("cfg-c"):
_ = clients, payload, user_id, db, error_prefix
if app_id == _normalized_provider_app_id("cfg-c"):
msg = "boom-update-connection"
raise RuntimeError(msg)
if created_app_ids_journal is not None:
created_app_ids_journal.append(app_id)
return app_id
async def mock_rollback_update_resources(*, clients, created_tool_ids, created_app_id, original_tools): # noqa: ARG001
@@ -2110,7 +2126,10 @@ async def test_apply_provider_update_plan_rolls_back_all_journaled_raw_connectio
plan=plan,
)
assert captured["rolled_back_app_ids"] == ["cfg-a", "cfg-b"]
assert captured["rolled_back_app_ids"] == [
_normalized_provider_app_id("cfg-a"),
_normalized_provider_app_id("cfg-b"),
]
@pytest.mark.anyio
@@ -2187,7 +2206,7 @@ async def test_apply_provider_update_plan_rolls_back_journaled_app_ids_when_crea
plan=plan,
)
assert captured["rolled_back_app_ids"] == ["cfg-a"]
assert captured["rolled_back_app_ids"] == [_normalized_provider_app_id("cfg-a")]
@pytest.mark.anyio
+430 -421
View File
File diff suppressed because it is too large Load Diff
+9 -8
View File
@@ -1,25 +1,26 @@
{
"name": "langflow",
"version": "1.9.0",
"version": "1.9.1",
"private": true,
"engines": {
"node": ">=20.19.0"
},
"overrides": {
"tar": "^7.5.7",
"tar-fs": ">=2.1.4",
"tar-fs": "^2.1.4",
"glob": "^11.1.0",
"test-exclude": "^7.0.0",
"picomatch": ">=4.0.4",
"picomatch": "^4.0.4",
"jest-util": {
"picomatch": ">=4.0.4"
"picomatch": "^4.0.4"
},
"jest-message-util": {
"picomatch": ">=4.0.4"
"picomatch": "^4.0.4"
},
"playwright": "^1.59.1",
"brace-expansion": ">=5.0.5",
"handlebars": ">=4.7.9"
"brace-expansion": "^5.0.5",
"handlebars": "^4.7.9",
"minimatch": "^10.2.5"
},
"dependencies": {
"@chakra-ui/number-input": "^2.1.2",
@@ -153,7 +154,7 @@
"@biomejs/biome": "2.1.1",
"@jest/types": "^30.0.1",
"@modelcontextprotocol/server-everything": "^2026.1.14",
"@playwright/test": "^1.57.0",
"@playwright/test": "^1.59.1",
"@storybook/addon-docs": "^10.1.0",
"@storybook/addon-links": "^10.1.0",
"@storybook/react": "^10.1.0",
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "lfx"
version = "0.4.0"
version = "0.4.1"
description = "Langflow Executor - A lightweight CLI tool for executing and serving Langflow AI flows"
readme = "README.md"
authors = [
File diff suppressed because one or more lines are too long
@@ -4,26 +4,12 @@ import shutil
from pathlib import Path
from typing import TYPE_CHECKING, cast
from toolguard.buildtime import (
PolicySpecOptions,
ToolGuardsCodeGenerationResult,
ToolGuardSpec,
generate_guard_specs,
generate_guards_code,
)
from toolguard.extra.langchain_to_oas import langchain_tools_to_openapi
from toolguard.runtime import load_toolguards, load_toolguards_from_memory
from toolguard.runtime.runtime import RESULTS_FILENAME
from lfx.base.models import LCModelComponent
from lfx.base.models.unified_models import (
get_language_model_options,
get_llm,
update_model_options_in_build_config,
)
from lfx.components.models_and_agents.policies.guard_sync_utils import sync_generated_guard_code_inputs
from lfx.components.models_and_agents.policies.guarded_tool import GuardedTool
from lfx.components.models_and_agents.policies.llm_wrapper import LangchainModelWrapper
from lfx.components.models_and_agents.policies.module_utils import unload_module
from lfx.field_typing import LanguageModel, Tool
from lfx.io import (
@@ -39,9 +25,77 @@ from lfx.io import (
from lfx.log.logger import logger
if TYPE_CHECKING:
from toolguard.buildtime import PolicySpecOptions, ToolGuardsCodeGenerationResult, ToolGuardSpec
from lfx.inputs.inputs import InputTypes
RESULTS_FILENAME = "results.json"
_TOOLGUARD_IMPORT_ERROR: ModuleNotFoundError | None = None
def _toolguard_error_message() -> str:
msg = (
"Policies component requires the optional `toolguard` dependency. "
"Install `langflow-base[toolguard]` or `langflow-base[complete]` to enable it."
)
if _TOOLGUARD_IMPORT_ERROR is not None:
return f"{msg} Original error: {_TOOLGUARD_IMPORT_ERROR}"
return msg
def _missing_toolguard_dependency(*_args, **_kwargs):
raise ImportError(_toolguard_error_message())
class _MissingToolguardType:
def __init__(self, *_args, **_kwargs):
raise ImportError(_toolguard_error_message())
def _sync_generated_guard_code_inputs_fallback(
build_config: dict,
work_dir: Path,
step2_subdir: str,
project_name: str,
) -> dict:
_ = work_dir, step2_subdir, project_name
return build_config
PolicySpecOptions = _MissingToolguardType
ToolGuardsCodeGenerationResult = _MissingToolguardType
generate_guard_specs = _missing_toolguard_dependency
generate_guards_code = _missing_toolguard_dependency
langchain_tools_to_openapi = _missing_toolguard_dependency
load_toolguards = _missing_toolguard_dependency
load_toolguards_from_memory = _missing_toolguard_dependency
GuardedTool = _MissingToolguardType
LangchainModelWrapper = _MissingToolguardType
sync_generated_guard_code_inputs = _sync_generated_guard_code_inputs_fallback
try:
from toolguard.buildtime import (
PolicySpecOptions,
ToolGuardsCodeGenerationResult,
generate_guard_specs,
generate_guards_code,
)
from toolguard.extra.langchain_to_oas import langchain_tools_to_openapi
from toolguard.runtime import load_toolguards, load_toolguards_from_memory
from toolguard.runtime.runtime import RESULTS_FILENAME
from lfx.components.models_and_agents.policies.guard_sync_utils import sync_generated_guard_code_inputs
from lfx.components.models_and_agents.policies.guarded_tool import GuardedTool
from lfx.components.models_and_agents.policies.llm_wrapper import LangchainModelWrapper
except ModuleNotFoundError as exc:
if not exc.name or not exc.name.startswith("toolguard"):
raise
_TOOLGUARD_IMPORT_ERROR = exc
TOOLGUARD_WORK_DIR = Path(os.getenv("TOOLGUARD_WORK_DIR") or "tmp_toolguard")
BUILDTIME_MODELS = ["gpt-5", "claude-sonnet"] # currently inactive, we recommend but do not enforce
STEP1 = "Step_1"
@@ -176,7 +230,7 @@ Powered by [ALTK ToolGuard](https://github.com/AgentToolkit/toolguard )"""
project_name=py_module,
)
async def _generate_guard_specs(self) -> list[ToolGuardSpec]:
async def _generate_guard_specs(self) -> list["ToolGuardSpec"]:
logger.debug("Starting step 1")
logger.debug(f"model = {self.model}")
llm = LangchainModelWrapper(self.build_model())
@@ -193,7 +247,7 @@ Powered by [ALTK ToolGuard](https://github.com/AgentToolkit/toolguard )"""
logger.debug("Step 1 Done")
return specs
async def _generate_guard_code(self, specs: list[ToolGuardSpec]) -> ToolGuardsCodeGenerationResult:
async def _generate_guard_code(self, specs: list["ToolGuardSpec"]) -> "ToolGuardsCodeGenerationResult":
logger.debug("Starting step 2")
out_dir = self.work_dir / STEP2
if out_dir.exists():
@@ -275,7 +329,7 @@ Powered by [ALTK ToolGuard](https://github.com/AgentToolkit/toolguard )"""
self._verify_cached_guards(code_dir)
def make_toolguard_result(self) -> ToolGuardsCodeGenerationResult:
def make_toolguard_result(self) -> "ToolGuardsCodeGenerationResult":
attrs = self.get_vertex().data["node"]["template"]
if not attrs:
raise ValueError
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "langflow-sdk"
version = "0.1.0"
version = "0.1.1"
description = "Python SDK for the Langflow REST API"
readme = "README.md"
requires-python = ">=3.10,<3.14"
Generated
+731 -643
View File
File diff suppressed because it is too large Load Diff