diff --git a/src/backend/base/langflow/components/data/URL.py b/src/backend/base/langflow/components/data/URL.py index 6f7a5391a..d27d17fe6 100644 --- a/src/backend/base/langflow/components/data/URL.py +++ b/src/backend/base/langflow/components/data/URL.py @@ -5,6 +5,8 @@ from langflow.inputs import StrInput from langflow.schema import Data from langflow.template import Output +import re + class URLComponent(Component): display_name = "URL" @@ -25,8 +27,39 @@ class URLComponent(Component): Output(display_name="Data", name="data", method="fetch_content"), ] + def ensure_url(self, string: str) -> str: + """ + Ensures the given string is a URL by adding 'http://' if it doesn't start with 'http://' or 'https://'. + Raises an error if the string is not a valid URL. + + Parameters: + string (str): The string to be checked and possibly modified. + + Returns: + str: The modified string that is ensured to be a URL. + + Raises: + ValueError: If the string is not a valid URL. + """ + if not string.startswith(("http://", "https://")): + string = "http://" + string + + # Basic URL validation regex + url_regex = re.compile( + r"^(http://|https://)?" # http:// or https:// + r"(([a-zA-Z0-9\.-]+)" # domain + r"(\.[a-zA-Z]{2,}))" # top-level domain + r"(:[0-9]{1,5})?" # optional port + r"(\/.*)?$" # optional path + ) + + if not re.match(url_regex, string): + raise ValueError(f"Invalid URL: {string}") + + return string + def fetch_content(self) -> Data: - urls = [url.strip() for url in self.urls if url.strip()] + urls = [self.ensure_url(url.strip()) for url in self.urls if url.strip()] loader = WebBaseLoader(web_paths=urls) docs = loader.load() data = [Data(content=doc.page_content, **doc.metadata) for doc in docs] diff --git a/src/backend/base/langflow/components/experimental/TextOperator.py b/src/backend/base/langflow/components/experimental/TextOperator.py index 73b472acf..84436e23b 100644 --- a/src/backend/base/langflow/components/experimental/TextOperator.py +++ b/src/backend/base/langflow/components/experimental/TextOperator.py @@ -1,90 +1,92 @@ -from typing import Union - from langflow.custom import Component from langflow.field_typing import Text -from langflow.schema import Data -from langflow.template import Input, Output +from langflow.inputs import BoolInput, DropdownInput, StrInput +from langflow.template import Output class TextOperatorComponent(Component): display_name = "Text Operator" description = "Compares two text inputs based on a specified condition such as equality or inequality, with optional case sensitivity." + icon = "equal" inputs = [ - Input(name="input_text", type=str, display_name="Input Text", info="The primary text input for the operation."), - Input(name="match_text", type=str, display_name="Match Text", info="The text input to compare against."), - Input( - name="operator", - type=str, - display_name="Operator", - info="The operator to apply for comparing the texts.", - options=["equals", "not equals", "contains", "starts with", "ends with", "exists"], + StrInput( + name="input_text", + display_name="Input Text", + info="The primary text input for the operation.", ), - Input( + StrInput( + name="match_text", + display_name="Match Text", + info="The text input to compare against.", + ), + DropdownInput( + name="operator", + display_name="Operator", + options=["equals", "not equals", "contains", "starts with", "ends with"], + info="The operator to apply for comparing the texts.", + ), + BoolInput( name="case_sensitive", - type=bool, display_name="Case Sensitive", info="If true, the comparison will be case sensitive.", - default=False, + value=False, + advanced=True, ), - Input( + StrInput( name="true_output", - type=Union[str, Data], display_name="True Output", info="The output to return or display when the comparison is true.", - input_types=["Text", "Data"], + advanced=True, ), - Input( + StrInput( name="false_output", - type=Union[str, Data], display_name="False Output", info="The output to return or display when the comparison is false.", - input_types=["Text", "Data"], + advanced=True, ), ] + outputs = [ - Output(display_name="True Result", name="true_result", method="result_response"), - Output(display_name="False Result", name="false_result", method="result_response"), + Output(display_name="True Result", name="true_result", method="true_response"), + Output(display_name="False Result", name="false_result", method="false_response"), ] - def true_response(self) -> Union[Text, Data]: - self.stop("False Result") - return self.true_output if self.true_output else self.input_text - - def false_response(self) -> Union[Text, Data]: - self.stop("True Result") - return self.false_output if self.false_output else self.input_text - - def result_response(self) -> Union[Text, Data]: - input_text = self.input_text - match_text = self.match_text - operator = self.operator - case_sensitive = self.case_sensitive - - if not input_text or not match_text: - raise ValueError("Both 'input_text' and 'match_text' must be provided and non-empty.") - + def evaluate_condition(self, input_text: str, match_text: str, operator: str, case_sensitive: bool) -> bool: if not case_sensitive: input_text = input_text.lower() match_text = match_text.lower() - result = False if operator == "equals": - result = input_text == match_text + return input_text == match_text elif operator == "not equals": - result = input_text != match_text + return input_text != match_text elif operator == "contains": - result = match_text in input_text + return match_text in input_text elif operator == "starts with": - result = input_text.startswith(match_text) + return input_text.startswith(match_text) elif operator == "ends with": - result = input_text.endswith(match_text) + return input_text.endswith(match_text) + return False + def true_response(self) -> Text: + result = self.evaluate_condition(self.input_text, self.match_text, self.operator, self.case_sensitive) if result: - response = self.true_response() + self.stop("false_result") + response = self.true_output if self.true_output else self.input_text self.status = response return response else: - response = self.false_response() + self.stop("true_result") + return "" + + def false_response(self) -> Text: + result = self.evaluate_condition(self.input_text, self.match_text, self.operator, self.case_sensitive) + if not result: + self.stop("true_result") + response = self.false_output if self.false_output else self.input_text self.status = response return response + else: + self.stop("false_result") + return "" diff --git a/src/backend/base/langflow/components/helpers/CombineText.py b/src/backend/base/langflow/components/helpers/CombineText.py index bedc4293d..641ab54ae 100644 --- a/src/backend/base/langflow/components/helpers/CombineText.py +++ b/src/backend/base/langflow/components/helpers/CombineText.py @@ -1,29 +1,38 @@ -from langflow.custom import CustomComponent +from langflow.custom import Component from langflow.field_typing import Text +from langflow.inputs import StrInput +from langflow.template import Output -class CombineTextComponent(CustomComponent): +class CombineTextComponent(Component): display_name = "Combine Text" description = "Concatenate two text sources into a single text chunk using a specified delimiter." icon = "merge" - def build_config(self): - return { - "text1": { - "display_name": "First Text", - "info": "The first text input to concatenate.", - }, - "text2": { - "display_name": "Second Text", - "info": "The second text input to concatenate.", - }, - "delimiter": { - "display_name": "Delimiter", - "info": "A string used to separate the two text inputs. Defaults to a whitespace.", - }, - } + inputs = [ + StrInput( + name="text1", + display_name="First Text", + info="The first text input to concatenate.", + ), + StrInput( + name="text2", + display_name="Second Text", + info="The second text input to concatenate.", + ), + StrInput( + name="delimiter", + display_name="Delimiter", + info="A string used to separate the two text inputs. Defaults to a whitespace.", + default=" ", + ), + ] - def build(self, text1: str, text2: str, delimiter: str = " ") -> Text: - combined = delimiter.join([text1, text2]) + outputs = [ + Output(display_name="Combined Text", name="combined_text", method="combine_texts"), + ] + + def combine_texts(self) -> Text: + combined = self.delimiter.join([self.text1, self.text2]) self.status = combined return combined diff --git a/src/backend/base/langflow/components/helpers/CombineTextsUnsorted.py b/src/backend/base/langflow/components/helpers/CombineTextsUnsorted.py deleted file mode 100644 index 67d315739..000000000 --- a/src/backend/base/langflow/components/helpers/CombineTextsUnsorted.py +++ /dev/null @@ -1,25 +0,0 @@ -from langflow.custom import CustomComponent -from langflow.field_typing import Text - - -class CombineTextsUnsortedComponent(CustomComponent): - display_name = "Combine Texts (Unsorted)" - description = "Concatenate text sources into a single text chunk using a specified delimiter." - icon = "merge" - - def build_config(self): - return { - "texts": { - "display_name": "Texts", - "info": "The first text input to concatenate.", - }, - "delimiter": { - "display_name": "Delimiter", - "info": "A string used to separate the two text inputs. Defaults to a whitespace.", - }, - } - - def build(self, texts: list[str], delimiter: str = " ") -> Text: - combined = delimiter.join(texts) - self.status = combined - return combined diff --git a/src/backend/base/langflow/components/helpers/DataToText.py b/src/backend/base/langflow/components/helpers/DataToText.py deleted file mode 100644 index 5bd688e9d..000000000 --- a/src/backend/base/langflow/components/helpers/DataToText.py +++ /dev/null @@ -1,36 +0,0 @@ -from langflow.custom import CustomComponent -from langflow.field_typing import Text -from langflow.helpers.data import data_to_text -from langflow.schema import Data - - -class DataToTextComponent(CustomComponent): - display_name = "Data To Text" - description = "Convert Data into plain text following a specified template." - - def build_config(self): - return { - "data": { - "display_name": "Data", - "info": "The data to convert to text.", - }, - "template": { - "display_name": "Template", - "info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.", - "multiline": True, - }, - } - - def build( - self, - data: list[Data], - template: str = "Text: {text}\nData: {data}", - ) -> Text: - if not data: - return "" - if isinstance(data, Data): - data = [data] - - result_string = data_to_text(template, data) - self.status = result_string - return result_string diff --git a/src/backend/base/langflow/components/helpers/DocumentToData.py b/src/backend/base/langflow/components/helpers/DocumentsToData.py similarity index 83% rename from src/backend/base/langflow/components/helpers/DocumentToData.py rename to src/backend/base/langflow/components/helpers/DocumentsToData.py index 44ba079a0..13111db59 100644 --- a/src/backend/base/langflow/components/helpers/DocumentToData.py +++ b/src/backend/base/langflow/components/helpers/DocumentsToData.py @@ -6,9 +6,10 @@ from langflow.custom import CustomComponent from langflow.schema import Data -class DocumentToDataComponent(CustomComponent): - display_name = "Documents To Data" +class DocumentsToDataComponent(CustomComponent): + display_name = "Documents ⇢ Data" description = "Convert LangChain Documents into Data." + icon = "LangChain" field_config = { "documents": {"display_name": "Documents"}, diff --git a/src/backend/base/langflow/components/helpers/FilterData.py b/src/backend/base/langflow/components/helpers/FilterData.py index db402502d..3d7cdbcec 100644 --- a/src/backend/base/langflow/components/helpers/FilterData.py +++ b/src/backend/base/langflow/components/helpers/FilterData.py @@ -1,20 +1,28 @@ from typing import List from langflow.custom import Component -from langflow.inputs import StrInput +from langflow.inputs import StrInput, HandleInput from langflow.schema import Data -from langflow.template import Input, Output +from langflow.template import Output class FilterDataComponent(Component): - display_name = "Filter Message" - description = "Filters a Message object based on a list of strings." + display_name = "Filter Data" + description = "Filters a Data object based on a list of keys." icon = "filter" inputs = [ - Input(name="message", display_name="Message", info="Message object to filter.", input_types=["Message"]), + HandleInput( + name="data", + display_name="Data", + info="Data object to filter.", + input_types=["Message", "Data"], + ), StrInput( - name="filter_criteria", display_name="Filter Criteria", info="List of strings to filter by.", is_list=True + name="filter_criteria", + display_name="Filter Criteria", + info="List of keys to filter by.", + is_list=True, ), ] @@ -24,10 +32,12 @@ class FilterDataComponent(Component): def filter_data(self) -> Data: filter_criteria: List[str] = self.filter_criteria + data = self.data.data if isinstance(self.data, Data) else {} # Filter the data - filtered = {key: value for key, value in self.message.data.items() if key == filter_criteria} + filtered = {key: value for key, value in data.items() if key in filter_criteria} # Create a new Data object with the filtered data - self.status = filtered - return filtered + filtered_data = Data(data=filtered) + self.status = filtered_data + return filtered_data diff --git a/src/backend/base/langflow/components/helpers/ParseData.py b/src/backend/base/langflow/components/helpers/ParseData.py new file mode 100644 index 000000000..41cd669fe --- /dev/null +++ b/src/backend/base/langflow/components/helpers/ParseData.py @@ -0,0 +1,34 @@ +from langflow.custom import Component +from langflow.helpers.data import data_to_text +from langflow.field_typing import Text +from langflow.inputs import MultilineInput, HandleInput +from langflow.template import Output + + +class ParseDataComponent(Component): + display_name = "Parse Data" + description = "Convert Data into plain text following a specified template." + icon = "braces" + + inputs = [ + HandleInput( + name="data", display_name="Data", info="The data to convert to text.", input_types=["Message", "Data"] + ), + MultilineInput( + name="template", + display_name="Template", + info="The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.", + ), + ] + + outputs = [ + Output(display_name="Text", name="text", method="parse_data_to_text"), + ] + + def parse_data_to_text(self) -> Text: + data = self.data if isinstance(self.data, list) else [self.data] + template = self.template or "Text: {text}" + + result_string = data_to_text(template, data) + self.status = result_string + return result_string diff --git a/src/backend/base/langflow/components/helpers/__init__.py b/src/backend/base/langflow/components/helpers/__init__.py index ee7ed977c..c10b83dd9 100644 --- a/src/backend/base/langflow/components/helpers/__init__.py +++ b/src/backend/base/langflow/components/helpers/__init__.py @@ -1,15 +1,15 @@ from .CreateData import CreateDataComponent from .CustomComponent import Component -from .DataToText import DataToTextComponent -from .DocumentToData import DocumentToDataComponent +from .ParseData import ParseDataComponent +from .DocumentToData import DocumentsToDataComponent from .IDGenerator import UUIDGeneratorComponent from .UpdateData import UpdateDataComponent __all__ = [ "Component", "UpdateDataComponent", - "DocumentToDataComponent", + "DocumentsToDataComponent", "UUIDGeneratorComponent", - "DataToTextComponent", + "ParseDataComponent", "CreateDataComponent", ] diff --git a/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py b/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py index 786d558bb..1c97c1e28 100644 --- a/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py +++ b/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py @@ -54,7 +54,7 @@ class ChatAntropicSpecsComponent(CustomComponent): self, model: str, anthropic_api_key: Optional[str] = None, - max_tokens: Optional[int] = None, + max_tokens: Optional[int] = 1000, temperature: Optional[float] = None, api_endpoint: Optional[str] = None, ) -> BaseLanguageModel: diff --git a/src/backend/base/langflow/components/model_specs/ChatAnthropicSpecs.py b/src/backend/base/langflow/components/model_specs/ChatAnthropicSpecs.py index 7e4000d9b..ce01320eb 100644 --- a/src/backend/base/langflow/components/model_specs/ChatAnthropicSpecs.py +++ b/src/backend/base/langflow/components/model_specs/ChatAnthropicSpecs.py @@ -66,7 +66,7 @@ class AnthropicLLM(CustomComponent): self, model: str, anthropic_api_key: Optional[str] = None, - max_tokens: Optional[int] = None, + max_tokens: Optional[int] = 1000, temperature: Optional[float] = None, anthropic_api_url: Optional[str] = None, ) -> BaseLanguageModel: diff --git a/src/backend/base/langflow/components/models/AnthropicModel.py b/src/backend/base/langflow/components/models/AnthropicModel.py index 4a7e1a330..f4695418b 100644 --- a/src/backend/base/langflow/components/models/AnthropicModel.py +++ b/src/backend/base/langflow/components/models/AnthropicModel.py @@ -82,7 +82,7 @@ class AnthropicLLM(LCModelComponent): input_value: Text, system_message: Optional[str] = None, anthropic_api_key: Optional[str] = None, - max_tokens: Optional[int] = None, + max_tokens: Optional[int] = 1000, temperature: Optional[float] = None, anthropic_api_url: Optional[str] = None, stream: bool = False, diff --git a/src/backend/base/langflow/custom/custom_component/component.py b/src/backend/base/langflow/custom/custom_component/component.py index 5d0af85c3..f13d8a0a2 100644 --- a/src/backend/base/langflow/custom/custom_component/component.py +++ b/src/backend/base/langflow/custom/custom_component/component.py @@ -98,10 +98,15 @@ class Component(CustomComponent): raw = self.status if hasattr(raw, "data") and raw is not None: raw = raw.data + if raw is None: + raw = custom_repr elif hasattr(raw, "model_dump") and raw is not None: raw = raw.model_dump() - artifact_type = get_artifact_type(self.status, result) + if raw is None and isinstance(result, (dict, Data, str)): + raw = result.data if isinstance(result, Data) else result + + artifact_type = get_artifact_type(self.repr_value or raw, result) raw = post_process_raw(raw, artifact_type) artifact = {"repr": custom_repr, "raw": raw, "type": artifact_type} _artifacts[output.name] = artifact @@ -110,21 +115,15 @@ class Component(CustomComponent): return _results, _artifacts def custom_repr(self): - # ! Temporary REPR - # Since all are dict, yaml.dump them - if isinstance(self._results, dict): - _build_results = recursive_serialize_or_str(self._results) - try: - custom_repr = yaml.dump(_build_results) - except Exception as e: - logger.error(f"Error while dumping build_result: {e}") - custom_repr = str(self._results) - - if custom_repr is None and isinstance(self._results, (dict, Data, str)): - custom_repr = self._results - if not isinstance(custom_repr, str): - custom_repr = str(custom_repr) - return custom_repr + if self.repr_value == "": + self.repr_value = self.status + if isinstance(self.repr_value, dict): + return yaml.dump(self.repr_value) + if isinstance(self.repr_value, str): + return self.repr_value + if isinstance(self.repr_value, BaseModel) and not isinstance(self.repr_value, Data): + return str(self.repr_value) + return self.repr_value def build_inputs(self, user_id: Optional[Union[str, UUID]] = None): """ diff --git a/src/backend/base/langflow/graph/schema.py b/src/backend/base/langflow/graph/schema.py index 0e99a5e84..825379800 100644 --- a/src/backend/base/langflow/graph/schema.py +++ b/src/backend/base/langflow/graph/schema.py @@ -35,8 +35,8 @@ class ResultData(BaseModel): message = values["artifacts"][key] # ! Temporary fix - if not isinstance(message, dict): - message = {"message": message} + if message is None: + continue if "stream_url" in message and "type" in message: stream_url = StreamURL(location=message["stream_url"]) diff --git a/src/backend/base/langflow/graph/vertex/base.py b/src/backend/base/langflow/graph/vertex/base.py index 17d364a03..bb0ddce23 100644 --- a/src/backend/base/langflow/graph/vertex/base.py +++ b/src/backend/base/langflow/graph/vertex/base.py @@ -234,16 +234,15 @@ class Vertex: self.has_session_id = "session_id" in template_dicts - self.required_inputs = [ - template_dicts[key]["type"] for key, value in template_dicts.items() if value["required"] - ] - self.optional_inputs = [ - template_dicts[key]["type"] for key, value in template_dicts.items() if not value["required"] - ] - # Add the template_dicts[key]["input_types"] to the optional_inputs - self.optional_inputs.extend( - [input_type for value in template_dicts.values() for input_type in value.get("input_types", [])] - ) + self.required_inputs = [] + self.optional_inputs = [] + for value_dict in template_dicts.values(): + list_to_append = self.required_inputs if value_dict.get("required") else self.optional_inputs + + if "type" in value_dict: + list_to_append.append(value_dict["type"]) + if "input_types" in value_dict: + list_to_append.extend(value_dict["input_types"]) template_dict = self.data["node"]["template"] self.vertex_type = ( diff --git a/src/backend/base/langflow/inputs/__init__.py b/src/backend/base/langflow/inputs/__init__.py index dd227d5db..53927ca0f 100644 --- a/src/backend/base/langflow/inputs/__init__.py +++ b/src/backend/base/langflow/inputs/__init__.py @@ -5,11 +5,12 @@ from .inputs import ( FileInput, FloatInput, IntInput, + MultilineInput, NestedDictInput, PromptInput, SecretStrInput, StrInput, - MultilineInput, + HandleInput, ) __all__ = [ @@ -24,4 +25,5 @@ __all__ = [ "FileInput", "PromptInput", "MultilineInput", + "HandleInput", ] diff --git a/src/backend/base/langflow/inputs/input_mixin.py b/src/backend/base/langflow/inputs/input_mixin.py index 917d1ea65..07e4f6338 100644 --- a/src/backend/base/langflow/inputs/input_mixin.py +++ b/src/backend/base/langflow/inputs/input_mixin.py @@ -25,7 +25,7 @@ SerializableFieldTypes = Annotated[FieldTypes, PlainSerializer(lambda v: v.value class BaseInputMixin(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) - field_type: Optional[SerializableFieldTypes] = Field(default=FieldTypes.TEXT) + field_type: Optional[SerializableFieldTypes | str] = Field(default=FieldTypes.TEXT) required: bool = False """Specifies if the field is required. Defaults to False.""" diff --git a/src/backend/base/langflow/inputs/inputs.py b/src/backend/base/langflow/inputs/inputs.py index a59a76984..c8146b2c2 100644 --- a/src/backend/base/langflow/inputs/inputs.py +++ b/src/backend/base/langflow/inputs/inputs.py @@ -1,6 +1,6 @@ from typing import Callable, Optional, Union -from pydantic import Field +from pydantic import Field, model_validator from langflow.inputs.validators import StrictBoolean @@ -16,6 +16,17 @@ from .input_mixin import ( ) +class HandleInput(BaseInputMixin): + input_types: list[str] = Field(default_factory=list) + field_type: Optional[str] = "" + + @model_validator(mode="after") + def validate_model_type(self): + # FieldType should be a string + self.field_type = " | ".join(self.input_types) + return self + + class PromptInput(BaseInputMixin, ListableInputMixin): field_type: Optional[SerializableFieldTypes] = FieldTypes.PROMPT @@ -24,6 +35,7 @@ class PromptInput(BaseInputMixin, ListableInputMixin): class StrInput(BaseInputMixin, ListableInputMixin, DatabaseLoadMixin): # noqa: F821 field_type: Optional[SerializableFieldTypes] = FieldTypes.TEXT load_from_db: StrictBoolean = False + input_types: list[str] = ["Text"] """Defines if the field will allow the user to open a text editor. Default is False.""" @@ -83,4 +95,5 @@ InputTypes = Union[ FileInput, PromptInput, MultilineInput, + HandleInput, ] diff --git a/src/backend/base/langflow/template/template/base.py b/src/backend/base/langflow/template/template/base.py index 72eb53fc2..ef6082cf8 100644 --- a/src/backend/base/langflow/template/template/base.py +++ b/src/backend/base/langflow/template/template/base.py @@ -23,7 +23,9 @@ class Template(BaseModel): # first sort alphabetically # then sort fields so that fields that have .field_type in DIRECT_TYPES are first self.fields.sort(key=lambda x: x.name) - self.fields.sort(key=lambda x: x.field_type in DIRECT_TYPES, reverse=False) + self.fields.sort( + key=lambda x: x.field_type in DIRECT_TYPES if hasattr(x, "field_type") else False, reverse=False + ) @model_serializer(mode="wrap") def serialize_model(self, handler): diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index fa64723c9..b24b834b8 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -302,6 +302,12 @@ export default function GenericNode({ ); }; + useEffect(() => { + if (hiddenOutputs && hiddenOutputs.length == 0) { + setShowHiddenOutputs(false); + } + }, [hiddenOutputs]); + const memoizedNodeToolbarComponent = useMemo(() => { return ( diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index 3865b9975..426c7dd2f 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -123,7 +123,7 @@ export const MenuBar = ({}: {}): JSX.Element => { title: UPLOAD_ERROR_ALERT, list: [error], }); - } + }, ); }} > @@ -193,7 +193,7 @@ export const MenuBar = ({}: {}): JSX.Element => { name="RefreshCcw" className="header-menu-options" /> - Reload Components + Refresh All @@ -221,7 +221,7 @@ export const MenuBar = ({}: {}): JSX.Element => { name={isBuilding || saveLoading ? "Loader2" : "CheckCircle2"} className={cn( "h-4 w-4", - isBuilding || saveLoading ? "animate-spin" : "animate-wiggle" + isBuilding || saveLoading ? "animate-spin" : "animate-wiggle", )} /> {printByBuildStatus()} diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index 21c8092a8..fff15809c 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -244,7 +244,7 @@ export const nodeColors: { [char: string]: string } = { outputs: "#AA2411", data: "#198BF6", prompts: "#4367BF", - models: "#6344BE", + models: "#ab11ab", model_specs: "#6344BE", chains: "#FE7500", Document: "#7AAE42", @@ -271,10 +271,10 @@ export const nodeColors: { [char: string]: string } = { Text: "#4367BF", retrievers: "#e6b25a", unknown: "#9CA3AF", - custom_components: "#ab11ab", - Data: "#31a3cc", - Data: "#31a3cc", + // custom_components: "#ab11ab", + Data: "#9CA3AF", Message: "#4367BF", + BaseLanguageModel: "#ab11ab", }; export const nodeNames: { [char: string]: string } = {