feat: redesign sidebar with new components and features (#4307)

* Added required ShadCN Components

* Added required colors

* Added required icons

* Changed backend to not return beta tag

* Added sidebar categories api call

* Added required use-mobile hook

* Refactored icons to allow sizing

* Added type for sidebar category

* Allowed no name on shortcut display

* Added flow sidebar component that uses ShadCN sidebar

* Added SidebarDraggableComponent with the new style

* Replaced sidebar with current one on FlowPage

* Added sidebar fixed footer with options to go to store and add custom component

* Updated sidebar categories

* Updated background color for sidebar

* Changed size of Components title

* Added color to PageComponent

* Added required icons

* added CustomComponent category and removed custom component from helpers

* create hook useAddComponent

* Use hook to add components both in PageComponent and flowSidebarComponent

* Implement search

* Implement searching and filtering by clicking on edge

* Added check to see if store is present

* Updated colors to match new color schema

* Changed styling of filter component

* Added Beta and Legacy badges

* Implement Show Beta Components and Show Legacy Components

* Fixed styling for sidebar config when collapsed

* Refactored search to filter for tags

* Refactor useeffect

* Updated config button styling

* Implemented keyboard navigation

* Fixed filtering

* Updated color of canvas

* Implemented disclosure on sidebar settings and fetched bundles

* Added temp sidebar bundles

* Fixed badge styling

* Added bundles to categories response in frontend

* Added legacy to components

* Added link to store instead of langflow.store

* Added required data-testids

* Fixed tests to use new data-testids and new sidebar disposition

* Fix github star bug

* Fixed tests that used the custom component

* Changed test to test beta and legacy checkers

* added a test for keyboard navigation on sidebar

* Added a test to check component add by hover the plus button

* [autofix.ci] apply automated fixes

* updated sidebar switch change

* Removed changes on Backend and used only Frontend constants for categories

* merge fix

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* 📝 (custom_component): Add CustomComponent class with input and output definitions
📝 (custom_component): Create CustomComponent class with display name, description, and documentation link
📝 (custom_component): Define input and output properties for CustomComponent class
📝 (custom_component): Implement build_output method in CustomComponent class
📝 (Ollama): Remove unnecessary whitespace in SvgOllama component

* formatting

* ♻️ (custom_component/__init__.py): refactor import statement to match the correct case of the file name for better consistency and readability

* 🔧 (FlowPage/index.tsx): remove FlowToolbar component when view prop is false to improve UI consistency

* 📝 (integration-side-bar.spec.ts): Comment out unnecessary code blocks related to API requests and modals to improve test readability and focus on the main test scenarios.

* [autofix.ci] apply automated fixes

* ✨ (flowSidebarComponent/index.tsx): add data-testid attribute to Sidebar component for testing purposes
🔧 (integration-side-bar.spec.ts): update test to use new data-testid attribute 'shad-sidebar' for Sidebar component to match changes in the codebase

* ✨ (stop-building.spec.ts): refactor test case to use a more descriptive test element for clicking on the sidebar custom component button

* format

* 🐛 (AstraDB): Fix variable naming inconsistency for isDark to isdark in AstraDB component
🐛 (HCD): Fix variable naming inconsistency for isDark to isdark in HCD component
🐛 (index.tsx): Fix variable naming inconsistency for isDark to isdark in index.tsx files
📝 (flowSidebarComponent): Refactor search functionality to normalize search terms and improve metadata search
📝 (filterEdge-shard-1.spec.ts): Update test to check visibility of specific model specs in the sidebar

* [autofix.ci] apply automated fixes

* ✅ (decisionFlow.spec.ts): add a delay of 500ms to ensure proper timing in the test case execution

* ✨ (decisionFlow.spec.ts): Update the X positions of elements in the flow to improve the visual representation and alignment of the elements.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: cristhianzl <cristhian.lousa@gmail.com>
This commit is contained in:
Lucas Oliveira 2024-10-31 19:51:36 -03:00 • committed by GitHub
commit 794848d5e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
122 changed files with 2365 additions and 802 deletions

View file

@ -6,7 +6,16 @@ from typing import TYPE_CHECKING, Annotated
from uuid import UUID
import sqlalchemy as sa
from fastapi import APIRouter, BackgroundTasks, Body, Depends, HTTPException, Request, UploadFile, status
from fastapi import (
APIRouter,
BackgroundTasks,
Body,
Depends,
HTTPException,
Request,
UploadFile,
status,
)
from loguru import logger
from sqlmodel import select
@ -17,7 +26,6 @@ from langflow.api.v1.schemas import (
CustomComponentResponse,
InputValueRequest,
RunResponse,
SidebarCategoriesResponse,
SimplifiedAPIRequest,
TaskStatusResponse,
UpdateCustomComponentRequest,
@ -37,7 +45,9 @@ from langflow.services.auth.utils import api_key_security, get_current_active_us
from langflow.services.cache.utils import save_uploaded_file
from langflow.services.database.models.flow import Flow
from langflow.services.database.models.flow.model import FlowRead
from langflow.services.database.models.flow.utils import get_all_webhook_components_in_flow
from langflow.services.database.models.flow.utils import (
get_all_webhook_components_in_flow,
)
from langflow.services.database.models.user.model import User, UserRead
from langflow.services.deps import (
get_session_service,
@ -47,7 +57,6 @@ from langflow.services.deps import (
)
from langflow.services.settings.feature_flags import FEATURE_FLAGS
from langflow.services.telemetry.schema import RunPayload
from langflow.utils.constants import SIDEBAR_CATEGORIES
from langflow.utils.version import get_version_info
if TYPE_CHECKING:
@ -110,7 +119,11 @@ async def simple_run_flow(
graph_data = process_tweaks(graph_data, input_request.tweaks or {}, stream=stream)
graph = Graph.from_payload(graph_data, flow_id=flow_id_str, user_id=str(user_id), flow_name=flow.name)
inputs = [
InputValueRequest(components=[], input_value=input_request.input_value, type=input_request.input_type)
InputValueRequest(
components=[],
input_value=input_request.input_value,
type=input_request.input_type,
)
]
if input_request.output_component:
outputs = [input_request.output_component]
@ -248,7 +261,10 @@ async def simplified_run_flow(
background_tasks.add_task(
telemetry_service.log_package_run,
RunPayload(
run_is_webhook=False, run_seconds=int(end_time - start_time), run_success=True, run_error_message=""
run_is_webhook=False,
run_seconds=int(end_time - start_time),
run_success=True,
run_error_message="",
),
)
@ -360,7 +376,11 @@ async def webhook_run_flow(
return {"message": "Task started in the background", "status": "in progress"}
@router.post("/run/advanced/{flow_id}", response_model=RunResponse, response_model_exclude_none=True)
@router.post(
"/run/advanced/{flow_id}",
response_model=RunResponse,
response_model_exclude_none=True,
)
async def experimental_run_flow(
*,
session: DbSession,
@ -631,11 +651,9 @@ async def get_config():
settings_service: SettingsService = get_settings_service()
return {"feature_flags": FEATURE_FLAGS, **settings_service.settings.model_dump()}
return {
"feature_flags": FEATURE_FLAGS,
**settings_service.settings.model_dump(),
}
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
@router.get("/sidebar_categories")
async def get_sidebar_categories() -> SidebarCategoriesResponse:
return SidebarCategoriesResponse(categories=SIDEBAR_CATEGORIES)

View file

@ -4,7 +4,14 @@ from pathlib import Path
from typing import Any
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator, model_serializer
from pydantic import (
BaseModel,
ConfigDict,
Field,
field_serializer,
field_validator,
model_serializer,
)
from langflow.graph.schema import RunOutputs
from langflow.graph.utils import serialize_field
@ -316,7 +323,11 @@ class InputValueRequest(BaseModel):
},
{"components": ["Component Name"], "input_value": "input_value"},
{"input_value": "input_value"},
{"components": ["Component Name"], "input_value": "input_value", "session": "session_id"},
{
"components": ["Component Name"],
"input_value": "input_value",
"session": "session_id",
},
{"input_value": "input_value", "session": "session_id"},
{"type": "chat", "input_value": "input_value"},
{"type": "json", "input_value": '{"key": "value"}'},
@ -357,14 +368,3 @@ class ConfigResponse(BaseModel):
auto_saving_interval: int
health_check_max_retries: int
max_file_size_upload: int
class SidebarCategory(BaseModel):
display_name: str
name: str
icon: str
beta: bool = False
class SidebarCategoriesResponse(BaseModel):
categories: list[SidebarCategory]

View file

@ -10,7 +10,15 @@ import orjson
STREAM_INFO_TEXT = "Stream the response from the model. Streaming works only in Chat."
NODE_FORMAT_ATTRIBUTES = ["beta", "icon", "display_name", "output_types", "edited", "metadata"]
NODE_FORMAT_ATTRIBUTES = [
"beta",
"legacy",
"icon",
"display_name",
"output_types",
"edited",
"metadata",
]
FIELD_FORMAT_ATTRIBUTES = [

View file

@ -1,6 +1,7 @@
from . import (
agents,
chains,
custom_component,
documentloaders,
embeddings,
helpers,
@ -26,6 +27,7 @@ __all__ = [
"helpers",
"inputs",
"link_extractors",
"custom_component",
"memories",
"models",
"output_parsers",

View file

@ -14,11 +14,22 @@ class JsonAgentComponent(LCAgentComponent):
display_name = "JsonAgent"
description = "Construct a json agent from an LLM and tools."
name = "JsonAgent"
legacy: bool = True
inputs = [
*LCAgentComponent._base_inputs,
HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True),
FileInput(name="path", display_name="File Path", file_types=["json", "yaml", "yml"], required=True),
HandleInput(
name="llm",
display_name="Language Model",
input_types=["LanguageModel"],
required=True,
),
FileInput(
name="path",
display_name="File Path",
file_types=["json", "yaml", "yml"],
required=True,
),
]
def build_agent(self) -> AgentExecutor:

View file

@ -9,11 +9,22 @@ class VectorStoreAgentComponent(LCAgentComponent):
display_name = "VectorStoreAgent"
description = "Construct an agent from a Vector Store."
name = "VectorStoreAgent"
legacy: bool = True
inputs = [
*LCAgentComponent._base_inputs,
HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True),
HandleInput(name="vectorstore", display_name="Vector Store", input_types=["VectorStoreInfo"], required=True),
HandleInput(
name="llm",
display_name="Language Model",
input_types=["LanguageModel"],
required=True,
),
HandleInput(
name="vectorstore",
display_name="Vector Store",
input_types=["VectorStoreInfo"],
required=True,
),
]
def build_agent(self) -> AgentExecutor:

View file

@ -9,10 +9,16 @@ class VectorStoreRouterAgentComponent(LCAgentComponent):
display_name = "VectorStoreRouterAgent"
description = "Construct an agent from a Vector Store Router."
name = "VectorStoreRouterAgent"
legacy: bool = True
inputs = [
*LCAgentComponent._base_inputs,
HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True),
HandleInput(
name="llm",
display_name="Language Model",
input_types=["LanguageModel"],
required=True,
),
HandleInput(
name="vectorstores",
display_name="Vector Stores",

View file

@ -9,12 +9,21 @@ class ConversationChainComponent(LCChainComponent):
display_name = "ConversationChain"
description = "Chain to have a conversation and load context from memory."
name = "ConversationChain"
legacy: bool = True
inputs = [
MultilineInput(
name="input_value", display_name="Input", info="The input value to pass to the chain.", required=True
name="input_value",
display_name="Input",
info="The input value to pass to the chain.",
required=True,
),
HandleInput(
name="llm",
display_name="Language Model",
input_types=["LanguageModel"],
required=True,
),
HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True),
HandleInput(
name="memory",
display_name="Memory",
@ -28,7 +37,10 @@ class ConversationChainComponent(LCChainComponent):
else:
chain = ConversationChain(llm=self.llm, memory=self.memory)
result = chain.invoke({"input": self.input_value}, config={"callbacks": self.get_langchain_callbacks()})
result = chain.invoke(
{"input": self.input_value},
config={"callbacks": self.get_langchain_callbacks()},
)
if isinstance(result, dict):
result = result.get(chain.output_key, "")

View file

@ -10,18 +10,28 @@ class LLMCheckerChainComponent(LCChainComponent):
description = "Chain for question-answering with self-verification."
documentation = "https://python.langchain.com/docs/modules/chains/additional/llm_checker"
name = "LLMCheckerChain"
legacy: bool = True
inputs = [
MultilineInput(
name="input_value", display_name="Input", info="The input value to pass to the chain.", required=True
name="input_value",
display_name="Input",
info="The input value to pass to the chain.",
required=True,
),
HandleInput(
name="llm",
display_name="Language Model",
input_types=["LanguageModel"],
required=True,
),
HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True),
]
def invoke_chain(self) -> Message:
chain = LLMCheckerChain.from_llm(llm=self.llm)
response = chain.invoke(
{chain.input_key: self.input_value}, config={"callbacks": self.get_langchain_callbacks()}
{chain.input_key: self.input_value},
config={"callbacks": self.get_langchain_callbacks()},
)
result = response.get(chain.output_key, "")
result = str(result)

View file

@ -11,12 +11,21 @@ class LLMMathChainComponent(LCChainComponent):
description = "Chain that interprets a prompt and executes python code to do math."
documentation = "https://python.langchain.com/docs/modules/chains/additional/llm_math"
name = "LLMMathChain"
legacy: bool = True
inputs = [
MultilineInput(
name="input_value", display_name="Input", info="The input value to pass to the chain.", required=True
name="input_value",
display_name="Input",
info="The input value to pass to the chain.",
required=True,
),
HandleInput(
name="llm",
display_name="Language Model",
input_types=["LanguageModel"],
required=True,
),
HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True),
]
outputs = [Output(display_name="Text", name="text", method="invoke_chain")]
@ -24,7 +33,8 @@ class LLMMathChainComponent(LCChainComponent):
def invoke_chain(self) -> Message:
chain = LLMMathChain.from_llm(llm=self.llm)
response = chain.invoke(
{chain.input_key: self.input_value}, config={"callbacks": self.get_langchain_callbacks()}
{chain.input_key: self.input_value},
config={"callbacks": self.get_langchain_callbacks()},
)
result = response.get(chain.output_key, "")
result = str(result)

View file

@ -9,10 +9,14 @@ class RetrievalQAComponent(LCChainComponent):
display_name = "Retrieval QA"
description = "Chain for question-answering querying sources from a retriever."
name = "RetrievalQA"
legacy: bool = True
inputs = [
MultilineInput(
name="input_value", display_name="Input", info="The input value to pass to the chain.", required=True
name="input_value",
display_name="Input",
info="The input value to pass to the chain.",
required=True,
),
DropdownInput(
name="chain_type",
@ -22,8 +26,18 @@ class RetrievalQAComponent(LCChainComponent):
value="Stuff",
advanced=True,
),
HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True),
HandleInput(name="retriever", display_name="Retriever", input_types=["Retriever"], required=True),
HandleInput(
name="llm",
display_name="Language Model",
input_types=["LanguageModel"],
required=True,
),
HandleInput(
name="retriever",
display_name="Retriever",
input_types=["Retriever"],
required=True,
),
HandleInput(
name="memory",
display_name="Memory",
@ -52,7 +66,10 @@ class RetrievalQAComponent(LCChainComponent):
return_source_documents=True,
)
result = runnable.invoke({"query": self.input_value}, config={"callbacks": self.get_langchain_callbacks()})
result = runnable.invoke(
{"query": self.input_value},
config={"callbacks": self.get_langchain_callbacks()},
)
source_docs = self.to_data(result.get("source_documents", keys=[]))
result_str = str(result.get("result", ""))

View file

@ -16,17 +16,38 @@ class SQLGeneratorComponent(LCChainComponent):
display_name = "Natural Language to SQL"
description = "Generate SQL from natural language."
name = "SQLGenerator"
legacy: bool = True
inputs = [
MultilineInput(
name="input_value", display_name="Input", info="The input value to pass to the chain.", required=True
name="input_value",
display_name="Input",
info="The input value to pass to the chain.",
required=True,
),
HandleInput(
name="llm",
display_name="Language Model",
input_types=["LanguageModel"],
required=True,
),
HandleInput(
name="db",
display_name="SQLDatabase",
input_types=["SQLDatabase"],
required=True,
),
HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True),
HandleInput(name="db", display_name="SQLDatabase", input_types=["SQLDatabase"], required=True),
IntInput(
name="top_k", display_name="Top K", info="The number of results per select statement to return.", value=5
name="top_k",
display_name="Top K",
info="The number of results per select statement to return.",
value=5,
),
MultilineInput(
name="prompt",
display_name="Prompt",
info="The prompt must contain `{question}`.",
),
MultilineInput(name="prompt", display_name="Prompt", info="The prompt must contain `{question}`."),
]
outputs = [Output(display_name="Text", name="text", method="invoke_chain")]
@ -48,7 +69,8 @@ class SQLGeneratorComponent(LCChainComponent):
sql_query_chain = create_sql_query_chain(llm=self.llm, db=self.db, prompt=prompt_template, k=self.top_k)
query_writer: Runnable = sql_query_chain | {"query": lambda x: x.replace("SQLQuery:", "").strip()}
response = query_writer.invoke(
{"question": self.input_value}, config={"callbacks": self.get_langchain_callbacks()}
{"question": self.input_value},
config={"callbacks": self.get_langchain_callbacks()},
)
query = response.get("query")
self.status = query

View file

@ -0,0 +1,5 @@
from .custom_component import CustomComponent
__all__ = [
"CustomComponent",
]

View file

@ -2,7 +2,6 @@ from .combine_text import CombineTextComponent
from .create_list import CreateListComponent
from .csv_to_data import CSVToDataComponent
from .current_date import CurrentDateComponent
from .custom_component import CustomComponent
from .data_conditional_router import DataConditionalRouterComponent
from .extract_key import ExtractDataKeyComponent
from .filter_data import FilterDataComponent
@ -25,7 +24,6 @@ __all__ = [
"CombineTextComponent",
"CreateListComponent",
"CurrentDateComponent",
"CustomComponent",
"DataConditionalRouterComponent",
"DataFilterComponent",
"ExtractDataKeyComponent",

View file

@ -21,6 +21,7 @@ class JSONDocumentBuilder(CustomComponent):
display_name: str = "JSON Document Builder"
description: str = "Build a Document containing a JSON object using a key and another Document page content."
name = "JSONDocumentBuilder"
legacy: bool = True
output_types: list[str] = ["Document"]
documentation: str = "https://docs.langflow.org/components/utilities#json-document-builder"

View file

@ -11,6 +11,7 @@ class AmazonKendraRetrieverComponent(CustomComponent):
description: str = "Retriever that uses the Amazon Kendra API."
name = "AmazonKendra"
icon = "Amazon"
legacy: bool = True
def build_config(self):
return {

View file

@ -3,7 +3,10 @@ from typing import cast
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank
from langflow.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store
from langflow.base.vectorstores.model import (
LCVectorStoreComponent,
check_cached_vector_store,
)
from langflow.field_typing import Retriever, VectorStore
from langflow.io import (
DropdownInput,
@ -22,6 +25,7 @@ class CohereRerankComponent(LCVectorStoreComponent):
description = "Rerank documents using the Cohere API and a retriever."
name = "CohereRerank"
icon = "Cohere"
legacy: bool = True
inputs = [
MultilineInput(

View file

@ -11,6 +11,7 @@ class MetalRetrieverComponent(CustomComponent):
display_name: str = "Metal Retriever"
description: str = "Retriever that uses the Metal API."
name = "MetalRetriever"
legacy: bool = True
def build_config(self):
return {

View file

@ -9,6 +9,7 @@ class MultiQueryRetrieverComponent(CustomComponent):
description = "Initialize from llm using default template."
documentation = "https://python.langchain.com/docs/modules/data_connection/retrievers/how_to/MultiQueryRetriever"
name = "MultiQueryRetriever"
legacy: bool = True
def build_config(self):
return {

View file

@ -2,9 +2,18 @@ from typing import Any, cast
from langchain.retrievers import ContextualCompressionRetriever
from langflow.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store
from langflow.base.vectorstores.model import (
LCVectorStoreComponent,
check_cached_vector_store,
)
from langflow.field_typing import Retriever, VectorStore
from langflow.io import DropdownInput, HandleInput, MultilineInput, SecretStrInput, StrInput
from langflow.io import (
DropdownInput,
HandleInput,
MultilineInput,
SecretStrInput,
StrInput,
)
from langflow.schema import Data
from langflow.schema.dotdict import dotdict
from langflow.template.field.base import Output
@ -14,6 +23,7 @@ class NvidiaRerankComponent(LCVectorStoreComponent):
display_name = "NVIDIA Rerank"
description = "Rerank documents using the NVIDIA API and a retriever."
icon = "NVIDIA"
legacy: bool = True
inputs = [
MultilineInput(
@ -28,7 +38,10 @@ class NvidiaRerankComponent(LCVectorStoreComponent):
info="The base URL of the NVIDIA API. Defaults to https://integrate.api.nvidia.com/v1.",
),
DropdownInput(
name="model", display_name="Model", options=["nv-rerank-qa-mistral-4b:1"], value="nv-rerank-qa-mistral-4b:1"
name="model",
display_name="Model",
options=["nv-rerank-qa-mistral-4b:1"],
value="nv-rerank-qa-mistral-4b:1",
),
SecretStrInput(name="api_key", display_name="API Key"),
HandleInput(name="retriever", display_name="Retriever", input_types=["Retriever"]),

View file

@ -13,6 +13,7 @@ class SelfQueryRetrieverComponent(Component):
description = "Retriever that uses a vector store and an LLM to generate the vector store queries."
name = "SelfQueryRetriever"
icon = "LangChain"
legacy: bool = True
inputs = [
HandleInput(
@ -48,7 +49,11 @@ class SelfQueryRetrieverComponent(Component):
]
outputs = [
Output(display_name="Retrieved Documents", name="documents", method="retrieve_documents"),
Output(
display_name="Retrieved Documents",
name="documents",
method="retrieve_documents",
),
]
def retrieve_documents(self) -> list[Data]:

View file

@ -8,6 +8,7 @@ class VectoStoreRetrieverComponent(CustomComponent):
display_name = "VectorStore Retriever"
description = "A vector store retriever"
name = "VectorStoreRetriever"
legacy: bool = True
def build_config(self):
return {

View file

@ -9,6 +9,7 @@ class VectorStoreInfoComponent(Component):
display_name = "VectorStoreInfo"
description = "Information about a VectorStore"
name = "VectorStoreInfo"
legacy: bool = True
inputs = [
MessageTextInput(
@ -41,5 +42,7 @@ class VectorStoreInfoComponent(Component):
"description": self.vectorstore_description,
}
return VectorStoreInfo(
vectorstore=self.input_vectorstore, description=self.vectorstore_description, name=self.vectorstore_name
vectorstore=self.input_vectorstore,
description=self.vectorstore_description,
name=self.vectorstore_name,
)

View file

@ -10,7 +10,14 @@ from pydantic.v1.fields import Undefined
from typing_extensions import override
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.inputs.inputs import BoolInput, DropdownInput, FieldTypes, HandleInput, MessageTextInput, MultilineInput
from langflow.inputs.inputs import (
BoolInput,
DropdownInput,
FieldTypes,
HandleInput,
MessageTextInput,
MultilineInput,
)
from langflow.io import Output
from langflow.schema import Data
from langflow.schema.dotdict import dotdict
@ -36,6 +43,7 @@ class PythonCodeStructuredTool(LCToolComponent):
name = "PythonCodeStructuredTool"
icon = "🐍"
field_order = ["name", "description", "tool_code", "return_direct", "tool_function"]
legacy: bool = True
inputs = [
MultilineInput(
@ -47,7 +55,12 @@ class PythonCodeStructuredTool(LCToolComponent):
real_time_refresh=True,
refresh_button=True,
),
MessageTextInput(name="tool_name", display_name="Tool Name", info="Enter the name of the tool.", required=True),
MessageTextInput(
name="tool_name",
display_name="Tool Name",
info="Enter the name of the tool.",
required=True,
),
MessageTextInput(
name="tool_description",
display_name="Description",
@ -192,7 +205,10 @@ class PythonCodeStructuredTool(LCToolComponent):
schema_annotation = Any
schema_fields[field_name] = (
schema_annotation,
Field(default=func_arg.get("default", Undefined), description=field_description),
Field(
default=func_arg.get("default", Undefined),
description=field_description,
),
)
if "temp_annotation_type" in _globals:
@ -214,7 +230,9 @@ class PythonCodeStructuredTool(LCToolComponent):
"""This function is called after the code validation is done."""
frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)
frontend_node["template"] = self.update_build_config(
frontend_node["template"], frontend_node["template"]["tool_code"]["value"], "tool_code"
frontend_node["template"],
frontend_node["template"]["tool_code"]["value"],
"tool_code",
)
frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)
for key in frontend_node["template"]:

View file

@ -19,6 +19,7 @@ class SearXNGToolComponent(LCToolComponent):
display_name = "SearXNG Search Tool"
description = "A component that searches for tools using SearXNG."
name = "SearXNGTool"
legacy: bool = True
inputs = [
MessageTextInput(
@ -127,7 +128,10 @@ class SearXNGToolComponent(LCToolComponent):
schema_fields = {
"query": (str, Field(..., description="The query to search for.")),
"categories": (list[str], Field(default=[], description="The categories to search in.")),
"categories": (
list[str],
Field(default=[], description="The categories to search in."),
),
}
searx_search_schema = create_model("SearxSearchSchema", **schema_fields)

View file

@ -61,6 +61,7 @@ ATTR_FUNC_MAPPING: dict[str, Callable] = {
"display_name": getattr_return_str,
"description": getattr_return_str,
"beta": getattr_return_bool,
"legacy": getattr_return_bool,
"documentation": getattr_return_str,
"icon": validate_icon,
"frozen": getattr_return_bool,

View file

@ -158,6 +158,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"lf_version": "1.0.16",
"metadata": {},
"output_types": [],
@ -380,6 +381,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"lf_version": "1.0.16",
"metadata": {},
"output_types": [],
@ -589,6 +591,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"lf_version": "1.0.16",
"metadata": {},
"output_types": [],
@ -1203,6 +1206,7 @@
],
"frozen": false,
"icon": "calculator",
"legacy": false,
"lf_version": "1.0.16",
"metadata": {},
"official": false,
@ -1322,6 +1326,7 @@
"code"
],
"frozen": false,
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [

View file

@ -108,6 +108,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -324,6 +325,7 @@
],
"frozen": false,
"icon": "prompts",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -445,6 +447,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -647,6 +650,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [

View file

@ -156,6 +156,7 @@
],
"frozen": false,
"icon": "layout-template",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -288,6 +289,7 @@
],
"frozen": false,
"icon": "braces",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -425,6 +427,7 @@
],
"frozen": false,
"icon": "prompts",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -667,6 +670,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -869,6 +873,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [

View file

@ -629,6 +629,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -876,6 +877,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1202,6 +1204,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1388,6 +1391,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1528,6 +1532,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1783,6 +1788,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -2043,6 +2049,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -2373,6 +2380,7 @@
"is_composition": null,
"is_input": null,
"is_output": null,
"legacy": false,
"metadata": {},
"name": "",
"output_types": [],
@ -2488,6 +2496,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -2814,6 +2823,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -3264,6 +3274,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -3738,6 +3749,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -4070,6 +4082,7 @@
"is_composition": null,
"is_input": null,
"is_output": null,
"legacy": false,
"metadata": {},
"name": "",
"output_types": [],
@ -4237,6 +4250,7 @@
"search_params"
],
"frozen": false,
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [

View file

@ -161,6 +161,7 @@
],
"frozen": false,
"icon": "prompts",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -306,6 +307,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -523,6 +525,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -725,6 +728,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1048,6 +1052,7 @@
],
"frozen": false,
"icon": "braces",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1181,6 +1186,7 @@
],
"frozen": false,
"icon": "file-text",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [

View file

@ -326,6 +326,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -576,6 +577,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -906,6 +908,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1097,6 +1100,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1242,6 +1246,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1501,6 +1506,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1763,6 +1769,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -2097,6 +2104,7 @@
"is_composition": null,
"is_input": null,
"is_output": null,
"legacy": false,
"metadata": {},
"name": "",
"output_types": [],
@ -2216,6 +2224,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -2436,6 +2445,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -2687,6 +2697,7 @@
"search_params"
],
"frozen": false,
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [

View file

@ -135,6 +135,7 @@
],
"frozen": false,
"icon": "prompts",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -280,6 +281,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -504,6 +506,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -830,6 +833,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1023,6 +1027,7 @@
],
"frozen": false,
"icon": "message-square-more",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [

View file

@ -389,6 +389,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -588,6 +589,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -915,6 +917,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -1199,6 +1202,7 @@
],
"frozen": false,
"icon": "prompts",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -1320,6 +1324,7 @@
],
"frozen": false,
"icon": "prompts",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -1441,6 +1446,7 @@
],
"frozen": false,
"icon": "prompts",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -1569,6 +1575,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -1920,6 +1927,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -2271,6 +2279,7 @@
],
"frozen": false,
"icon": "CrewAI",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],

View file

@ -398,6 +398,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -620,6 +621,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
@ -829,6 +831,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1442,6 +1445,7 @@
"search_params"
],
"frozen": false,
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"official": false,
@ -2319,6 +2323,7 @@
],
"frozen": false,
"icon": "calculator",
"legacy": false,
"lf_version": "1.0.15",
"metadata": {},
"official": false,

View file

@ -291,6 +291,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -524,6 +525,7 @@
],
"frozen": false,
"icon": "AstraDB",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1020,6 +1022,7 @@
],
"frozen": false,
"icon": "braces",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1157,6 +1160,7 @@
],
"frozen": false,
"icon": "prompts",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1302,6 +1306,7 @@
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1494,6 +1499,7 @@
],
"frozen": false,
"icon": "scissors-line-dashed",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1639,6 +1645,7 @@
],
"frozen": false,
"icon": "file-text",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -1788,6 +1795,7 @@
],
"frozen": false,
"icon": "AstraDB",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -2302,6 +2310,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -2778,6 +2787,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [
@ -3246,6 +3256,7 @@
],
"frozen": false,
"icon": "OpenAI",
"legacy": false,
"metadata": {},
"output_types": [],
"outputs": [

View file

@ -49,6 +49,8 @@ class FrontendNode(BaseModel):
"""Order of the fields in the frontend node."""
beta: bool = False
"""Whether the frontend node is in beta."""
legacy: bool = False
"""Whether the frontend node is legacy."""
error: str | None = None
"""Error message for the frontend node."""
edited: bool = False
@ -81,7 +83,10 @@ class FrontendNode(BaseModel):
if "output_types" in result and not result.get("outputs"):
for base_class in result["output_types"]:
output = Output(
display_name=base_class, name=base_class.lower(), types=[base_class], selected=base_class
display_name=base_class,
name=base_class.lower(),
types=[base_class],
selected=base_class,
)
result["outputs"].append(output.model_dump())

View file

@ -47,6 +47,7 @@ class CustomComponentFrontendNode(FrontendNode):
name: str = "CustomComponent"
display_name: str | None = "CustomComponent"
beta: bool = False
legacy: bool = False
template: Template = Template(
type_name="CustomComponent",
fields=[
@ -72,6 +73,7 @@ class ComponentFrontendNode(FrontendNode):
name: str = "Component"
display_name: str | None = "Component"
beta: bool = False
legacy: bool = False
template: Template = Template(
type_name="Component",
fields=[

View file

@ -52,7 +52,18 @@ def python_function(text: str) -> str:
PYTHON_BASIC_TYPES = [str, bool, int, float, tuple, list, dict, set]
DIRECT_TYPES = ["str", "bool", "dict", "int", "float", "Any", "prompt", "code", "NestedDict", "table"]
DIRECT_TYPES = [
"str",
"bool",
"dict",
"int",
"float",
"Any",
"prompt",
"code",
"NestedDict",
"table",
]
LOADERS_INFO: list[dict[str, Any]] = [
@ -175,29 +186,3 @@ MESSAGE_SENDER_NAME_AI = "AI"
MESSAGE_SENDER_NAME_USER = "User"
MAX_TEXT_LENGTH = 99999
SIDEBAR_CATEGORIES = [
{"display_name": "Saved", "name": "saved_components", "icon": "GradientSave"},
{"display_name": "Inputs", "name": "inputs", "icon": "Download"},
{"display_name": "Outputs", "name": "outputs", "icon": "Upload"},
{"display_name": "Prompts", "name": "prompts", "icon": "TerminalSquare"},
{"display_name": "Data", "name": "data", "icon": "Database"},
{"display_name": "Models", "name": "models", "icon": "BrainCircuit"},
{"display_name": "Helpers", "name": "helpers", "icon": "Wand2"},
{"display_name": "Vector Stores", "name": "vectorstores", "icon": "Layers"},
{"display_name": "Embeddings", "name": "embeddings", "icon": "Binary"},
{"display_name": "Agents", "name": "agents", "icon": "Bot"},
{"display_name": "Astra Assistants", "name": "astra_assistants", "icon": "Sparkles"},
{"display_name": "Chains", "name": "chains", "icon": "Link"},
{"display_name": "Loaders", "name": "documentloaders", "icon": "Paperclip"},
{"display_name": "Utilities", "name": "langchain_utilities", "icon": "PocketKnife"},
{"display_name": "Link Extractors", "name": "link_extractors", "icon": "Link2"},
{"display_name": "Memories", "name": "memories", "icon": "Cpu"},
{"display_name": "Output Parsers", "name": "output_parsers", "icon": "Compass"},
{"display_name": "Prototypes", "name": "prototypes", "icon": "FlaskConical"},
{"display_name": "Retrievers", "name": "retrievers", "icon": "FileSearch"},
{"display_name": "Text Splitters", "name": "textsplitters", "icon": "Scissors"},
{"display_name": "Toolkits", "name": "toolkits", "icon": "Package2"},
{"display_name": "Tools", "name": "tools", "icon": "Hammer"},
]