Merge branch 'dev' into two_edges_dev
This commit is contained in:
commit
2d692a6701
10 changed files with 163 additions and 133 deletions
83
.github/workflows/docker-build.yml
vendored
83
.github/workflows/docker-build.yml
vendored
|
|
@ -23,14 +23,23 @@ env:
|
|||
POETRY_VERSION: "1.8.2"
|
||||
|
||||
jobs:
|
||||
docker_build:
|
||||
name: Build Docker Image
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
base_tags: ${{ steps.set-vars.outputs.base_tags }}
|
||||
main_tags: ${{ steps.set-vars.outputs.main_tags }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set Dockerfile and Tags
|
||||
id: set-vars
|
||||
run: |
|
||||
echo "base_tags=langflowai/langflow:base-${{ inputs.version }}" >> $GITHUB_OUTPUT
|
||||
echo "main_tags=langflowai/langflow:${{ inputs.version }},langflowai/langflow:1.0-alpha" >> $GITHUB_OUTPUT
|
||||
build_base:
|
||||
runs-on: ubuntu-latest
|
||||
needs: setup
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
id: qemu
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Hub
|
||||
|
|
@ -38,56 +47,54 @@ jobs:
|
|||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Set Dockerfile and Tags
|
||||
id: set-vars
|
||||
run: |
|
||||
if [ "${{ inputs.release_type }}" == "base" ]; then
|
||||
echo "DOCKERFILE=./docker/build_and_push_base.Dockerfile" >> $GITHUB_ENV
|
||||
echo "TAGS=langflowai/langflow:base-${{ inputs.version }}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "DOCKERFILE=./docker/build_and_push.Dockerfile" >> $GITHUB_ENV
|
||||
echo "TAGS=langflowai/langflow:${{ inputs.version }},langflowai/langflow:1.0-alpha" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Build and push
|
||||
- name: Build and push Base Image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: "linux/amd64,linux/arm64/v8"
|
||||
file: ${{ env.DOCKERFILE }}
|
||||
tags: ${{ env.TAGS }}
|
||||
- name: Wait for Docker Hub to propagate
|
||||
run: sleep 120
|
||||
- name: Build and push (backend)
|
||||
if: ${{ inputs.release_type == 'main' }}
|
||||
file: ./docker/build_and_push_base.Dockerfile
|
||||
tags: ${{ needs.setup.outputs.base_tags }}
|
||||
|
||||
build_components:
|
||||
if: ${{ inputs.release_type == 'main' }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build_base
|
||||
strategy:
|
||||
matrix:
|
||||
component: [backend, frontend]
|
||||
include:
|
||||
- component: backend
|
||||
dockerfile: ./docker/build_and_push_backend.Dockerfile
|
||||
tags: langflowai/langflow-backend:${{ inputs.version }},langflowai/langflow-backend:1.0-alpha
|
||||
- component: frontend
|
||||
dockerfile: ./docker/frontend/build_and_push_frontend.Dockerfile
|
||||
tags: langflowai/langflow-frontend:${{ inputs.version }},langflowai/langflow-frontend:1.0-alpha
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push ${{ matrix.component }}
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: "linux/amd64,linux/arm64/v8"
|
||||
file: ./docker/build_and_push_backend.Dockerfile
|
||||
build-args: |
|
||||
LANGFLOW_IMAGE=langflowai/langflow:${{ inputs.version }}
|
||||
tags: |
|
||||
langflowai/langflow-backend:${{ inputs.version }}
|
||||
langflowai/langflow-backend:1.0-alpha
|
||||
- name: Build and push (frontend)
|
||||
if: ${{ inputs.release_type == 'main' }}
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: ./docker/frontend/build_and_push_frontend.Dockerfile
|
||||
platforms: "linux/amd64,linux/arm64/v8"
|
||||
tags: |
|
||||
langflowai/langflow-frontend:${{ inputs.version }}
|
||||
langflowai/langflow-frontend:1.0-alpha
|
||||
file: ${{ matrix.dockerfile }}
|
||||
tags: ${{ matrix.tags }}
|
||||
|
||||
restart-space:
|
||||
name: Restart HuggingFace Spaces
|
||||
if: ${{ inputs.release_type == 'main' }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_build
|
||||
needs: build_base
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
|
|
|
|||
51
poetry.lock
generated
51
poetry.lock
generated
|
|
@ -471,17 +471,17 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "boto3"
|
||||
version = "1.34.125"
|
||||
version = "1.34.126"
|
||||
description = "The AWS SDK for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "boto3-1.34.125-py3-none-any.whl", hash = "sha256:116d9eb3c26cf313a2e1e44ef704d1f98f9eb18e7628695d07b01b44a8683544"},
|
||||
{file = "boto3-1.34.125.tar.gz", hash = "sha256:31c4a5e4d6f9e6116be61ff654b424ddbd1afcdefe0e8b870c4796f9108eb1c6"},
|
||||
{file = "boto3-1.34.126-py3-none-any.whl", hash = "sha256:7f676daef674fe74f34ce4063228eccc6e60c811f574720e31f230296c4bf29a"},
|
||||
{file = "boto3-1.34.126.tar.gz", hash = "sha256:7e8418b47dd43954a9088d504541bed8a42b6d06e712d02befba134c1c4d7c6d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
botocore = ">=1.34.125,<1.35.0"
|
||||
botocore = ">=1.34.126,<1.35.0"
|
||||
jmespath = ">=0.7.1,<2.0.0"
|
||||
s3transfer = ">=0.10.0,<0.11.0"
|
||||
|
||||
|
|
@ -490,13 +490,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
|
|||
|
||||
[[package]]
|
||||
name = "botocore"
|
||||
version = "1.34.125"
|
||||
version = "1.34.126"
|
||||
description = "Low-level, data-driven core of boto 3."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "botocore-1.34.125-py3-none-any.whl", hash = "sha256:71e97e7d2c088f1188ba6976441b5857a5425acd4aaa31b45d13119c9cb86424"},
|
||||
{file = "botocore-1.34.125.tar.gz", hash = "sha256:d2882be011ad5b16e7ab4a96360b5b66a0a7e175c1ea06dbf2de473c0a0a33d8"},
|
||||
{file = "botocore-1.34.126-py3-none-any.whl", hash = "sha256:7eff883c638fe30e0b036789df32d851e093d12544615a3b90062b42ac85bdbc"},
|
||||
{file = "botocore-1.34.126.tar.gz", hash = "sha256:7a8ccb6a7c02456757a984a3a44331b6f51c94cb8b9b287cd045122fd177a4b0"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -4113,22 +4113,25 @@ adal = ["adal (>=1.0.2)"]
|
|||
|
||||
[[package]]
|
||||
name = "langchain"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
description = "Building applications with LLMs through composability"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langchain-0.2.3-py3-none-any.whl", hash = "sha256:5dc33cd9c8008693d328b7cb698df69073acecc89ad9c2a95f243b3314f8d834"},
|
||||
{file = "langchain-0.2.3.tar.gz", hash = "sha256:81962cc72cce6515f7bd71e01542727870789bf8b666c6913d85559080c1a201"},
|
||||
{file = "langchain-0.2.4-py3-none-any.whl", hash = "sha256:a04813215c30f944df006031e2febde872af8fab628dcee825d969e07b6cd621"},
|
||||
{file = "langchain-0.2.4.tar.gz", hash = "sha256:e704b5b06222d5eba2d02c76f891321d1bac8952ed54e093831b2bdabf99dcd5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
aiohttp = ">=3.8.3,<4.0.0"
|
||||
async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""}
|
||||
langchain-core = ">=0.2.0,<0.3.0"
|
||||
langchain-core = ">=0.2.6,<0.3.0"
|
||||
langchain-text-splitters = ">=0.2.0,<0.3.0"
|
||||
langsmith = ">=0.1.17,<0.2.0"
|
||||
numpy = ">=1,<2"
|
||||
numpy = [
|
||||
{version = ">=1,<2", markers = "python_version < \"3.12\""},
|
||||
{version = ">=1.26.0,<2.0.0", markers = "python_version >= \"3.12\""},
|
||||
]
|
||||
pydantic = ">=1,<3"
|
||||
PyYAML = ">=5.3"
|
||||
requests = ">=2,<3"
|
||||
|
|
@ -4224,19 +4227,19 @@ tenacity = ">=8.1.0,<9.0.0"
|
|||
|
||||
[[package]]
|
||||
name = "langchain-core"
|
||||
version = "0.2.5"
|
||||
version = "0.2.6"
|
||||
description = "Building applications with LLMs through composability"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langchain_core-0.2.5-py3-none-any.whl", hash = "sha256:abe5138f22acff23a079ec538be5268bbf97cf023d51987a0dd474d2a16cae3e"},
|
||||
{file = "langchain_core-0.2.5.tar.gz", hash = "sha256:4a5c2f56b22396a63ef4790043660e393adbfa6832b978f023ca996a04b8e752"},
|
||||
{file = "langchain_core-0.2.6-py3-none-any.whl", hash = "sha256:90521c9fc95d8f925e0d2e2d952382676aea6d3f8de611eda1b1810874c31e5d"},
|
||||
{file = "langchain_core-0.2.6.tar.gz", hash = "sha256:9f0e38da722a558a6e95b6d86de01bd92e84558c47ac8ba599f02eab70a1c873"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
jsonpatch = ">=1.33,<2.0"
|
||||
langsmith = ">=0.1.66,<0.2.0"
|
||||
packaging = ">=23.2,<24.0"
|
||||
langsmith = ">=0.1.75,<0.2.0"
|
||||
packaging = ">=23.2,<25"
|
||||
pydantic = ">=1,<3"
|
||||
PyYAML = ">=5.3"
|
||||
tenacity = ">=8.1.0,<9.0.0"
|
||||
|
|
@ -4409,7 +4412,7 @@ six = "*"
|
|||
|
||||
[[package]]
|
||||
name = "langflow-base"
|
||||
version = "0.0.66"
|
||||
version = "0.0.68"
|
||||
description = "A Python package with a built-in web application"
|
||||
optional = false
|
||||
python-versions = ">=3.10,<3.13"
|
||||
|
|
@ -4506,13 +4509,13 @@ requests = ">=2,<3"
|
|||
|
||||
[[package]]
|
||||
name = "litellm"
|
||||
version = "1.40.9"
|
||||
version = "1.40.12"
|
||||
description = "Library to easily interface with LLM API providers"
|
||||
optional = false
|
||||
python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8"
|
||||
files = [
|
||||
{file = "litellm-1.40.9-py3-none-any.whl", hash = "sha256:8a4107b9cce114d822de52cbc9bce56f8edc6620f19d0f2257e71834715fb366"},
|
||||
{file = "litellm-1.40.9.tar.gz", hash = "sha256:e0ea07d0b55001a6f60bba2b2ecd72d1f0dca07e656f63937adfdf45f31e5ad7"},
|
||||
{file = "litellm-1.40.12-py3-none-any.whl", hash = "sha256:42f1648507f29c60543ba5fdf35d38fc161694da043b201508225bae50d3328c"},
|
||||
{file = "litellm-1.40.12.tar.gz", hash = "sha256:366bb9c3694b9ef59b3d073bb37ff9ca175ab4090dc187b0a11d2b21db3a6a5d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -7850,13 +7853,13 @@ websockets = ">=11,<13"
|
|||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "5.0.5"
|
||||
version = "5.0.6"
|
||||
description = "Python client for Redis database and key-value store"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "redis-5.0.5-py3-none-any.whl", hash = "sha256:30b47d4ebb6b7a0b9b40c1275a19b87bb6f46b3bed82a89012cf56dea4024ada"},
|
||||
{file = "redis-5.0.5.tar.gz", hash = "sha256:3417688621acf6ee368dec4a04dd95881be24efd34c79f00d31f62bb528800ae"},
|
||||
{file = "redis-5.0.6-py3-none-any.whl", hash = "sha256:c0d6d990850c627bbf7be01c5c4cbaadf67b48593e913bb71c9819c30df37eee"},
|
||||
{file = "redis-5.0.6.tar.gz", hash = "sha256:38473cd7c6389ad3e44a91f4c3eaf6bcb8a9f746007f29bf4fb20824ff0b2197"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "langflow"
|
||||
version = "1.0.0a55"
|
||||
version = "1.0.0a57"
|
||||
description = "A Python package with a built-in web application"
|
||||
authors = ["Langflow <contact@langflow.org>"]
|
||||
maintainers = [
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import warnings
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Annotated, Coroutine, Optional, Union
|
||||
from uuid import UUID
|
||||
import warnings
|
||||
|
||||
from cryptography.fernet import Fernet
|
||||
from fastapi import Depends, HTTPException, Security, status
|
||||
from fastapi.security import APIKeyHeader, APIKeyQuery, OAuth2PasswordBearer
|
||||
|
||||
|
||||
from jose import JWTError, jwt
|
||||
from loguru import logger
|
||||
from sqlmodel import Session
|
||||
from starlette.websockets import WebSocket
|
||||
|
||||
|
|
@ -92,44 +91,58 @@ async def get_current_user_by_jwt(
|
|||
) -> User:
|
||||
settings_service = get_settings_service()
|
||||
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
if isinstance(token, Coroutine):
|
||||
token = await token
|
||||
|
||||
if settings_service.auth_settings.SECRET_KEY.get_secret_value() is None:
|
||||
raise credentials_exception
|
||||
secret_key = settings_service.auth_settings.SECRET_KEY.get_secret_value()
|
||||
if secret_key is None:
|
||||
logger.error("Secret key is not set in settings.")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
# Careful not to leak sensitive information
|
||||
detail="Authentication failure: Verify authentication settings.",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
try:
|
||||
# Ignore warning about datetime.utcnow
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
settings_service.auth_settings.SECRET_KEY.get_secret_value(),
|
||||
algorithms=[settings_service.auth_settings.ALGORITHM],
|
||||
)
|
||||
user_id: UUID = payload.get("sub") # type: ignore
|
||||
token_type: str = payload.get("type") # type: ignore
|
||||
payload = jwt.decode(token, secret_key, algorithms=[settings_service.auth_settings.ALGORITHM])
|
||||
user_id: UUID = payload.get("sub")
|
||||
token_type: str = payload.get("type")
|
||||
if expires := payload.get("exp", None):
|
||||
expires_datetime = datetime.fromtimestamp(expires, timezone.utc)
|
||||
# TypeError: can't compare offset-naive and offset-aware datetimes
|
||||
if datetime.now(timezone.utc) > expires_datetime:
|
||||
raise credentials_exception
|
||||
logger.info("Token expired for user")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Token has expired.",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
if user_id is None or token_type:
|
||||
raise credentials_exception
|
||||
logger.info(f"Invalid token payload. Token type: {token_type}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid token details.",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
except JWTError as e:
|
||||
raise credentials_exception from e
|
||||
logger.error(f"JWT decoding error: {e}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
) from e
|
||||
|
||||
user = get_user_by_id(db, user_id) # type: ignore
|
||||
user = get_user_by_id(db, user_id)
|
||||
if user is None or not user.is_active:
|
||||
raise credentials_exception
|
||||
logger.info("User not found or inactive.")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="User not found or is inactive.",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
return user
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,24 +6,21 @@ from typing import TYPE_CHECKING
|
|||
import sqlalchemy as sa
|
||||
from alembic import command, util
|
||||
from alembic.config import Config
|
||||
from loguru import logger
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.exc import OperationalError
|
||||
from sqlalchemy.engine import Engine
|
||||
from sqlalchemy import event
|
||||
from sqlmodel import Session, SQLModel, create_engine, select, text
|
||||
|
||||
from langflow.services.base import Service
|
||||
from langflow.services.database import models # noqa
|
||||
from langflow.services.database.models.user.crud import get_user_by_username
|
||||
from langflow.services.database.utils import Result, TableResults
|
||||
from langflow.services.deps import get_settings_service
|
||||
from langflow.services.utils import teardown_superuser
|
||||
from loguru import logger
|
||||
from sqlalchemy import event, inspect
|
||||
from sqlalchemy.engine import Engine
|
||||
from sqlalchemy.exc import OperationalError
|
||||
from sqlmodel import Session, SQLModel, create_engine, select, text
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sqlalchemy.engine import Engine
|
||||
|
||||
from langflow.services.settings.service import SettingsService
|
||||
from sqlalchemy.engine import Engine
|
||||
|
||||
|
||||
class DatabaseService(Service):
|
||||
|
|
@ -48,12 +45,23 @@ class DatabaseService(Service):
|
|||
connect_args = {"check_same_thread": False}
|
||||
else:
|
||||
connect_args = {}
|
||||
return create_engine(
|
||||
self.database_url,
|
||||
connect_args=connect_args,
|
||||
pool_size=self.settings_service.settings.pool_size,
|
||||
max_overflow=self.settings_service.settings.max_overflow,
|
||||
)
|
||||
try:
|
||||
return create_engine(
|
||||
self.database_url,
|
||||
connect_args=connect_args,
|
||||
pool_size=self.settings_service.settings.pool_size,
|
||||
max_overflow=self.settings_service.settings.max_overflow,
|
||||
)
|
||||
except sa.exc.NoSuchModuleError as exc:
|
||||
# sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres
|
||||
if "postgres" in str(exc) and not self.database_url.startswith("postgresql"):
|
||||
# https://stackoverflow.com/questions/62688256/sqlalchemy-exc-nosuchmoduleerror-cant-load-plugin-sqlalchemy-dialectspostgre
|
||||
self.database_url = self.database_url.replace("postgres://", "postgresql://")
|
||||
logger.warning(
|
||||
"Fixed postgres dialect in database URL. Replacing postgres:// with postgresql://. To avoid this warning, update the database URL."
|
||||
)
|
||||
return self._create_engine()
|
||||
raise RuntimeError("Error creating database engine") from exc
|
||||
|
||||
@event.listens_for(Engine, "connect")
|
||||
def on_connection(dbapi_connection, connection_record):
|
||||
|
|
|
|||
31
src/backend/base/poetry.lock
generated
31
src/backend/base/poetry.lock
generated
|
|
@ -1158,22 +1158,25 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "langchain"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
description = "Building applications with LLMs through composability"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langchain-0.2.3-py3-none-any.whl", hash = "sha256:5dc33cd9c8008693d328b7cb698df69073acecc89ad9c2a95f243b3314f8d834"},
|
||||
{file = "langchain-0.2.3.tar.gz", hash = "sha256:81962cc72cce6515f7bd71e01542727870789bf8b666c6913d85559080c1a201"},
|
||||
{file = "langchain-0.2.4-py3-none-any.whl", hash = "sha256:a04813215c30f944df006031e2febde872af8fab628dcee825d969e07b6cd621"},
|
||||
{file = "langchain-0.2.4.tar.gz", hash = "sha256:e704b5b06222d5eba2d02c76f891321d1bac8952ed54e093831b2bdabf99dcd5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
aiohttp = ">=3.8.3,<4.0.0"
|
||||
async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""}
|
||||
langchain-core = ">=0.2.0,<0.3.0"
|
||||
langchain-core = ">=0.2.6,<0.3.0"
|
||||
langchain-text-splitters = ">=0.2.0,<0.3.0"
|
||||
langsmith = ">=0.1.17,<0.2.0"
|
||||
numpy = ">=1,<2"
|
||||
numpy = [
|
||||
{version = ">=1,<2", markers = "python_version < \"3.12\""},
|
||||
{version = ">=1.26.0,<2.0.0", markers = "python_version >= \"3.12\""},
|
||||
]
|
||||
pydantic = ">=1,<3"
|
||||
PyYAML = ">=5.3"
|
||||
requests = ">=2,<3"
|
||||
|
|
@ -1205,19 +1208,19 @@ tenacity = ">=8.1.0,<9.0.0"
|
|||
|
||||
[[package]]
|
||||
name = "langchain-core"
|
||||
version = "0.2.5"
|
||||
version = "0.2.6"
|
||||
description = "Building applications with LLMs through composability"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langchain_core-0.2.5-py3-none-any.whl", hash = "sha256:abe5138f22acff23a079ec538be5268bbf97cf023d51987a0dd474d2a16cae3e"},
|
||||
{file = "langchain_core-0.2.5.tar.gz", hash = "sha256:4a5c2f56b22396a63ef4790043660e393adbfa6832b978f023ca996a04b8e752"},
|
||||
{file = "langchain_core-0.2.6-py3-none-any.whl", hash = "sha256:90521c9fc95d8f925e0d2e2d952382676aea6d3f8de611eda1b1810874c31e5d"},
|
||||
{file = "langchain_core-0.2.6.tar.gz", hash = "sha256:9f0e38da722a558a6e95b6d86de01bd92e84558c47ac8ba599f02eab70a1c873"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
jsonpatch = ">=1.33,<2.0"
|
||||
langsmith = ">=0.1.66,<0.2.0"
|
||||
packaging = ">=23.2,<24.0"
|
||||
langsmith = ">=0.1.75,<0.2.0"
|
||||
packaging = ">=23.2,<25"
|
||||
pydantic = ">=1,<3"
|
||||
PyYAML = ">=5.3"
|
||||
tenacity = ">=8.1.0,<9.0.0"
|
||||
|
|
@ -1859,13 +1862,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.2"
|
||||
version = "24.1"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
|
||||
{file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
|
||||
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
||||
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "langflow-base"
|
||||
version = "0.0.66"
|
||||
version = "0.0.68"
|
||||
description = "A Python package with a built-in web application"
|
||||
authors = ["Langflow <contact@langflow.org>"]
|
||||
maintainers = [
|
||||
|
|
|
|||
|
|
@ -16,19 +16,19 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
|||
get().setLoading(true);
|
||||
getFolders().then(
|
||||
(res) => {
|
||||
const foldersWithoutStarterProjects = res.filter(
|
||||
(folder) => folder.name !== STARTER_FOLDER_NAME
|
||||
const foldersWithoutStarterProjects = res?.filter(
|
||||
(folder) => folder.name !== STARTER_FOLDER_NAME,
|
||||
);
|
||||
|
||||
const starterProjects = res.find(
|
||||
(folder) => folder.name === STARTER_FOLDER_NAME
|
||||
const starterProjects = res?.find(
|
||||
(folder) => folder.name === STARTER_FOLDER_NAME,
|
||||
);
|
||||
|
||||
set({ starterProjectId: starterProjects!.id ?? "" });
|
||||
set({ folders: foldersWithoutStarterProjects });
|
||||
|
||||
const myCollectionId = res?.find(
|
||||
(f) => f.name === DEFAULT_FOLDER
|
||||
(f) => f.name === DEFAULT_FOLDER,
|
||||
)?.id;
|
||||
|
||||
set({ myCollectionId });
|
||||
|
|
@ -45,7 +45,7 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
|||
set({ folders: [] });
|
||||
get().setLoading(false);
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
@ -54,24 +54,21 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
|||
loading: false,
|
||||
setLoading: (loading) => set(() => ({ loading: loading })),
|
||||
getFolderById: (id) => {
|
||||
get().setLoadingById(true);
|
||||
if (id) {
|
||||
getFolderById(id).then(
|
||||
(res) => {
|
||||
const setAllFlows = useFlowsManagerStore.getState().setAllFlows;
|
||||
setAllFlows(res.flows);
|
||||
set({ selectedFolder: res });
|
||||
get().setLoadingById(false);
|
||||
},
|
||||
() => {
|
||||
get().setLoadingById(false);
|
||||
}
|
||||
get().getFoldersApi(true);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
selectedFolder: null,
|
||||
loadingById: false,
|
||||
setLoadingById: (loading) => set(() => ({ loadingById: loading })),
|
||||
getMyCollectionFolder: () => {
|
||||
const folders = get().folders;
|
||||
const myCollectionId = folders?.find((f) => f.name === DEFAULT_FOLDER)?.id;
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ export type FoldersStoreType = {
|
|||
setLoading: (loading: boolean) => void;
|
||||
selectedFolder: FolderType | null;
|
||||
getFolderById: (id: string) => void;
|
||||
loadingById: boolean;
|
||||
setLoadingById: (loading: boolean) => void;
|
||||
getMyCollectionFolder: () => void;
|
||||
myCollectionFlows: FolderType | null;
|
||||
myCollectionId: string | null;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from langflow.services.auth.utils import create_super_user, get_password_hash
|
||||
from langflow.services.database.models.user import UserUpdate
|
||||
from langflow.services.database.models.user.model import User
|
||||
|
|
@ -95,7 +96,7 @@ def test_data_consistency_after_update(client, active_user, logged_in_headers, s
|
|||
# Fetch the updated user from the database
|
||||
response = client.get("/api/v1/users/whoami", headers=logged_in_headers)
|
||||
assert response.status_code == 401, response.json()
|
||||
assert response.json()["detail"] == "Could not validate credentials"
|
||||
assert response.json()["detail"] == "User not found or is inactive."
|
||||
|
||||
|
||||
def test_data_consistency_after_delete(client, test_user, super_user_headers):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue