Refactor "created_at" column type for consistency and fix cancel middleware (#2316)

* chore: update linting workflows to include dev branch in merge_group

* Update README.md

Add 1.0 banner

* Update README.md

* chore: update package versions in pyproject.toml files

* refactor: update "created_at" column type to use the "sa" module for consistency

* Update README.md

Add 1.0 banner

* chore: Remove unused import in ToolCallingAgent.py

* fix: adapt RequestCancelledMiddleware to handle cancelled requests

* chore: Remove unused import in test_helper_components.py

* refactor: Declare queue variable with explicit type in RequestCancelledMiddleware

---------

Co-authored-by: Rodrigo Nader <rodrigosilvanader@gmail.com>
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-06-24 12:39:49 -07:00 • committed by GitHub
commit 77e23d9442
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 25 additions and 30 deletions

View file

@ -42,6 +42,7 @@
# 📝 Content # 📝 Content
- [](#)
- [📝 Content](#-content) - [📝 Content](#-content)
- [📦 Get Started](#-get-started) - [📦 Get Started](#-get-started)
- [🎨 Create Flows](#-create-flows) - [🎨 Create Flows](#-create-flows)
@ -49,6 +50,7 @@
- [Deploy Langflow on Google Cloud Platform](#deploy-langflow-on-google-cloud-platform) - [Deploy Langflow on Google Cloud Platform](#deploy-langflow-on-google-cloud-platform)
- [Deploy on Railway](#deploy-on-railway) - [Deploy on Railway](#deploy-on-railway)
- [Deploy on Render](#deploy-on-render) - [Deploy on Render](#deploy-on-render)
- [Deploy on Kubernetes](#deploy-on-kubernetes)
- [🖥️ Command Line Interface (CLI)](#️-command-line-interface-cli) - [🖥️ Command Line Interface (CLI)](#️-command-line-interface-cli)
- [Usage](#usage) - [Usage](#usage)
- [Environment Variables](#environment-variables) - [Environment Variables](#environment-variables)

View file

@ -34,7 +34,7 @@ def upgrade() -> None:
sa.Column("provider", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("provider", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.Column("created_at", sqlmodel.sql.sqltypes.DateTime(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=True), sa.Column("updated_at", sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint("id"), sa.PrimaryKeyConstraint("id"),
) )

View file

@ -2,7 +2,6 @@ from typing import Dict, List, cast
from langchain.agents import AgentExecutor, BaseSingleActionAgent from langchain.agents import AgentExecutor, BaseSingleActionAgent
from langchain.agents.tool_calling_agent.base import create_tool_calling_agent from langchain.agents.tool_calling_agent.base import create_tool_calling_agent
from langchain_core.messages import BaseMessage
from langchain_core.prompts import ChatPromptTemplate from langchain_core.prompts import ChatPromptTemplate
from langflow.custom import Component from langflow.custom import Component

View file

@ -6,7 +6,7 @@ from typing import Optional
from urllib.parse import urlencode from urllib.parse import urlencode
import nest_asyncio # type: ignore import nest_asyncio # type: ignore
from fastapi import FastAPI, Request from fastapi import FastAPI, Request, Response
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
@ -32,22 +32,17 @@ from langflow.utils.logger import configure
warnings.filterwarnings("ignore", category=PydanticDeprecatedSince20) warnings.filterwarnings("ignore", category=PydanticDeprecatedSince20)
class RequestCancelledMiddleware: class RequestCancelledMiddleware(BaseHTTPMiddleware):
def __init__(self, app): def __init__(self, app):
self.app = app super().__init__(app)
async def __call__(self, scope, receive, send): async def dispatch(self, request: Request, call_next):
if scope["type"] != "http": queue: asyncio.Queue = asyncio.Queue()
await self.app(scope, receive, send)
return
# Let's make a shared queue for the request messages async def message_poller(sentinel, handler_task, request):
queue = asyncio.Queue()
async def message_poller(sentinel, handler_task):
nonlocal queue nonlocal queue
while True: while True:
message = await receive() message = await request.receive
if message["type"] == "http.disconnect": if message["type"] == "http.disconnect":
handler_task.cancel() handler_task.cancel()
return sentinel # Break the loop return sentinel # Break the loop
@ -56,13 +51,14 @@ class RequestCancelledMiddleware:
await queue.put(message) await queue.put(message)
sentinel = object() sentinel = object()
handler_task = asyncio.create_task(self.app(scope, queue.get, send)) handler_task = asyncio.create_task(call_next(request))
asyncio.create_task(message_poller(sentinel, handler_task)) asyncio.create_task(message_poller(sentinel, handler_task, request))
try: try:
return await handler_task response = await handler_task
return response
except asyncio.CancelledError: except asyncio.CancelledError:
pass return Response("Request was cancelled", status_code=499)
class JavaScriptMIMETypeMiddleware(BaseHTTPMiddleware): class JavaScriptMIMETypeMiddleware(BaseHTTPMiddleware):

View file

@ -1,5 +1,3 @@
from langchain_core.documents import Document
from langflow.components import helpers from langflow.components import helpers
from langflow.custom.utils import build_custom_component_template from langflow.custom.utils import build_custom_component_template
from langflow.schema import Data from langflow.schema import Data
@ -17,18 +15,18 @@ from langflow.schema import Data
# assert result.new_key == "new_value" # assert result.new_key == "new_value"
def test_document_to_data_component(): # def test_document_to_data_component():
# Arrange # # Arrange
document_to_data_component = helpers.DocumentsToDataComponent() # document_to_data_component = helpers.DocumentsToDataComponent()
# Act # # Act
# Replace with your actual test data # # Replace with your actual test data
document = Document(page_content="key: value", metadata={"url": "https://example.com"}) # document = Document(page_content="key: value", metadata={"url": "https://example.com"})
result = document_to_data_component.build(document) # result = document_to_data_component.build(document)
# Assert # # Assert
# Replace with your actual expected result # # Replace with your actual expected result
assert result == [Data(data={"text": "key: value", "url": "https://example.com"})] # assert result == [Data(data={"text": "key: value", "url": "https://example.com"})]
def test_uuid_generator_component(): def test_uuid_generator_component():