diff --git a/src/backend/base/langflow/api/utils.py b/src/backend/base/langflow/api/utils.py index 1dbd68d8f..82bd32165 100644 --- a/src/backend/base/langflow/api/utils.py +++ b/src/backend/base/langflow/api/utils.py @@ -219,7 +219,7 @@ async def build_and_cache_graph_from_db(flow_id: str, session: Session, chat_ser if vertex is None: raise ValueError(f"Vertex {vertex_id} not found") if not vertex._raw_params.get("session_id"): - vertex.update_raw_params({"session_id": flow_id}) + vertex.update_raw_params({"session_id": flow_id}, overwrite=True) await chat_service.set_cache(flow_id, graph) return graph diff --git a/src/backend/base/langflow/components/outputs/RecordsOutput.py b/src/backend/base/langflow/components/outputs/RecordsOutput.py index c750e675b..cbd268ea6 100644 --- a/src/backend/base/langflow/components/outputs/RecordsOutput.py +++ b/src/backend/base/langflow/components/outputs/RecordsOutput.py @@ -16,4 +16,5 @@ class RecordOutput(CustomComponent): } def build(self, input_value: Record) -> Record: + self.status = input_value return input_value diff --git a/src/backend/base/langflow/components/retrievers/SelfQueryRetriever.py b/src/backend/base/langflow/components/retrievers/SelfQueryRetriever.py new file mode 100644 index 000000000..a46bf7bd8 --- /dev/null +++ b/src/backend/base/langflow/components/retrievers/SelfQueryRetriever.py @@ -0,0 +1,39 @@ +# from langflow.field_typing import Data +from langchain.chains.query_constructor.base import AttributeInfo +from langchain.retrievers.self_query.base import SelfQueryRetriever +from langchain_core.vectorstores import VectorStore + +from langflow.custom import CustomComponent +from langflow.field_typing import BaseLanguageModel +from langflow.schema import Record +from langflow.schema.message import Message + + +class SelfQueryRetrieverComponent(CustomComponent): + display_name: str = "Self Query Retriever" + description: str = "Retriever that uses a vector store and an LLM to generate the vector store queries." + icon = "LangChain" + + def build( + self, + query: Message, + vectorstore: VectorStore, + metadata_field_info: list[AttributeInfo], + document_content_description: str, + llm: BaseLanguageModel, + ) -> Record: + metadata_field_info = [i[0] for i in metadata_field_info] + + self_query_retriever = SelfQueryRetriever.from_llm( + llm, + vectorstore, + document_content_description, + metadata_field_info, + enable_limit=True, + ) + + input_text = query.text + documents = self_query_retriever.invoke(input=input_text) + records = [Record.from_document(document) for document in documents] + self.status = records + return records diff --git a/src/backend/base/langflow/custom/custom_component/custom_component.py b/src/backend/base/langflow/custom/custom_component/custom_component.py index 896b07337..5c1da081b 100644 --- a/src/backend/base/langflow/custom/custom_component/custom_component.py +++ b/src/backend/base/langflow/custom/custom_component/custom_component.py @@ -126,8 +126,11 @@ class CustomComponent(Component): @staticmethod def resolve_path(path: str) -> str: """Resolves the path to an absolute path.""" + if not path: + return path path_object = Path(path) - if path_object.parts[0] == "~": + + if path_object.parts and path_object.parts[0] == "~": path_object = path_object.expanduser() elif path_object.is_relative_to("."): path_object = path_object.resolve() diff --git a/src/backend/base/langflow/field_typing/prompt.py b/src/backend/base/langflow/field_typing/prompt.py index ef6c7ce9a..029261ac7 100644 --- a/src/backend/base/langflow/field_typing/prompt.py +++ b/src/backend/base/langflow/field_typing/prompt.py @@ -25,6 +25,7 @@ class Prompt(Record): prompt_template = PromptTemplate.from_template(self.template) variables_with_str_values = dict_values_to_string(self.variables) formatted_prompt = prompt_template.format(**variables_with_str_values) + self.text = formatted_prompt return formatted_prompt @classmethod diff --git a/src/backend/base/langflow/schema/record.py b/src/backend/base/langflow/schema/record.py index 830f576ba..67d9b5da8 100644 --- a/src/backend/base/langflow/schema/record.py +++ b/src/backend/base/langflow/schema/record.py @@ -1,12 +1,12 @@ import copy import json -from typing import cast, Optional +from typing import Optional, cast from langchain_core.documents import Document from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage +from langchain_core.prompt_values import ImagePromptValue from langchain_core.prompts.image import ImagePromptTemplate from pydantic import BaseModel, model_serializer, model_validator -from langchain_core.prompt_values import ImagePromptValue class Record(BaseModel): @@ -200,3 +200,6 @@ class Record(BaseModel): def __contains__(self, key): return key in self.data + + def __eq__(self, other): + return isinstance(other, Record) and self.data == other.data diff --git a/src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx index 307c77c1a..437adb511 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx @@ -28,7 +28,7 @@ export default function SwitchOutputView(nodeId): JSX.Element { if (resultMessage.raw) { resultMessage = resultMessage.raw; } - console.log("resultType", results); + return ( <> diff --git a/src/frontend/src/components/tableComponent/components/TableOptions/index.tsx b/src/frontend/src/components/tableComponent/components/TableOptions/index.tsx index 7ad2d11f3..dcf246fda 100644 --- a/src/frontend/src/components/tableComponent/components/TableOptions/index.tsx +++ b/src/frontend/src/components/tableComponent/components/TableOptions/index.tsx @@ -1,7 +1,7 @@ import { cn } from "../../../../utils/utils"; +import IconComponent from "../../../genericIconComponent"; import ShadTooltip from "../../../shadTooltipComponent"; import { Button } from "../../../ui/button"; -import IconComponent from "../../../genericIconComponent"; export default function TableOptions({ resetGrid, @@ -18,7 +18,7 @@ export default function TableOptions({ }): JSX.Element { return (
-
+
@@ -81,8 +84,8 @@ export default function TableOptions({ diff --git a/src/frontend/src/icons/LangChain/LangChainIcon.jsx b/src/frontend/src/icons/LangChain/LangChainIcon.jsx new file mode 100644 index 000000000..c68bd3f4f --- /dev/null +++ b/src/frontend/src/icons/LangChain/LangChainIcon.jsx @@ -0,0 +1,10 @@ +const SvgLangChainIcon = (props) => ( + + + + + + + +); +export default SvgLangChainIcon; diff --git a/src/frontend/src/icons/LangChain/index.tsx b/src/frontend/src/icons/LangChain/index.tsx new file mode 100644 index 000000000..48b8566e1 --- /dev/null +++ b/src/frontend/src/icons/LangChain/index.tsx @@ -0,0 +1,9 @@ +import React, { forwardRef } from "react"; +import SvgLangChainIcon from "./LangChainIcon"; + +export const LangChainIcon = forwardRef< + SVGSVGElement, + React.PropsWithChildren<{}> +>((props, ref) => { + return ; +}); diff --git a/src/frontend/src/icons/LangChain/langchain-icon.svg b/src/frontend/src/icons/LangChain/langchain-icon.svg new file mode 100644 index 000000000..e80068b50 --- /dev/null +++ b/src/frontend/src/icons/LangChain/langchain-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/frontend/src/modals/IOModal/components/IOFieldView/index.tsx b/src/frontend/src/modals/IOModal/components/IOFieldView/index.tsx index 7b1fba1ca..0bf856aef 100644 --- a/src/frontend/src/modals/IOModal/components/IOFieldView/index.tsx +++ b/src/frontend/src/modals/IOModal/components/IOFieldView/index.tsx @@ -254,7 +254,11 @@ export default function IOFieldView({
artifact.data + ) ?? [] + } columnMode="union" />
diff --git a/src/frontend/src/modals/editNodeModal/index.tsx b/src/frontend/src/modals/editNodeModal/index.tsx index 47ecb4291..abf1cc6e4 100644 --- a/src/frontend/src/modals/editNodeModal/index.tsx +++ b/src/frontend/src/modals/editNodeModal/index.tsx @@ -3,6 +3,7 @@ import { forwardRef, useEffect, useRef, useState } from "react"; import IconComponent from "../../components/genericIconComponent"; import TableComponent from "../../components/tableComponent"; import { Badge } from "../../components/ui/badge"; +import { useDarkStore } from "../../stores/darkStore"; import useFlowStore from "../../stores/flowStore"; import { NodeDataType } from "../../types/flow"; import BaseModal from "../baseModal"; @@ -29,6 +30,8 @@ const EditNodeModal = forwardRef( ) => { const myData = useRef(cloneDeep(data)); + const isDark = useDarkStore((state) => state.dark); + const setNode = useFlowStore((state) => state.setNode); function changeAdvanced(n) { @@ -72,7 +75,9 @@ const EditNodeModal = forwardRef( {data.type} - ID: {data.id} + + ID: {data.id} +
diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index c78fdf10d..fd2190e53 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -180,6 +180,7 @@ export default function Page({ function handleUndo(e: KeyboardEvent) { e.preventDefault(); + e.stopImmediatePropagation(); if (!isWrappedWithClass(e, "noundo")) { undo(); } @@ -187,6 +188,7 @@ export default function Page({ function handleRedo(e: KeyboardEvent) { e.preventDefault(); + e.stopImmediatePropagation(); if (!isWrappedWithClass(e, "noundo")) { redo(); } @@ -194,6 +196,7 @@ export default function Page({ function handleGroup(e: KeyboardEvent) { e.preventDefault(); + e.stopImmediatePropagation(); if (selectionMenuVisible) { handleGroupNode(); } @@ -202,6 +205,7 @@ export default function Page({ function handleDuplicate(e: KeyboardEvent) { e.preventDefault(); e.stopPropagation(); + e.stopImmediatePropagation(); const selectedNode = nodes.filter((obj) => obj.selected); if (selectedNode.length > 0) { paste( @@ -216,6 +220,7 @@ export default function Page({ function handleCopy(e: KeyboardEvent) { e.preventDefault(); + e.stopImmediatePropagation(); if ( !isWrappedWithClass(e, "nocopy") && window.getSelection()?.toString().length === 0 && @@ -227,6 +232,7 @@ export default function Page({ function handleCut(e: KeyboardEvent) { e.preventDefault(); + e.stopImmediatePropagation(); if ( !isWrappedWithClass(e, "nocopy") && window.getSelection()?.toString().length === 0 && @@ -238,6 +244,7 @@ export default function Page({ function handlePaste(e: KeyboardEvent) { e.preventDefault(); + e.stopImmediatePropagation(); if ( !isWrappedWithClass(e, "nocopy") && window.getSelection()?.toString().length === 0 && @@ -253,6 +260,7 @@ export default function Page({ function handleDelete(e: KeyboardEvent) { e.preventDefault(); + e.stopImmediatePropagation(); if (!isWrappedWithClass(e, "nodelete") && lastSelection) { takeSnapshot(); deleteNode(lastSelection.nodes.map((node) => node.id)); diff --git a/src/frontend/src/pages/MainPage/components/headerComponent/index.tsx b/src/frontend/src/pages/MainPage/components/headerComponent/index.tsx index f4e518e19..151cdd902 100644 --- a/src/frontend/src/pages/MainPage/components/headerComponent/index.tsx +++ b/src/frontend/src/pages/MainPage/components/headerComponent/index.tsx @@ -107,7 +107,7 @@ const HeaderComponent = ({ name="Trash2" className={cn( "h-5 w-5 text-primary transition-all", - disableFunctions ? "" : "hover:text-destructive", + disableFunctions ? "" : "hover:text-status-red", )} /> diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index c0b271849..d792a0d6c 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -23,7 +23,7 @@ export const useShortcutsStore = create((set, get) => ({ group: "mod+g", cut: "mod+x", paste: "mod+v", - api: "mod+r", + api: "mod+shift+r", update: "mod+u", download: "mod+j", freeze: "mod+f", diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index 123702b60..9a65e4f27 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -1,5 +1,6 @@ import { AlertCircle, + AlertTriangle, ArrowBigUp, ArrowLeft, ArrowUpToLine, @@ -116,7 +117,6 @@ import { Settings, Settings2, Share, - AlertTriangle, Share2, Shield, Sliders, @@ -146,11 +146,10 @@ import { Variable, Wand2, Workflow, + Wrench, X, XCircle, Zap, - PlaySquare, - Wrench, } from "lucide-react"; import { FaApple, FaDiscord, FaGithub } from "react-icons/fa"; import { AWSIcon } from "../icons/AWS"; @@ -177,6 +176,7 @@ import { import { GroqIcon } from "../icons/Groq"; import { HuggingFaceIcon } from "../icons/HuggingFace"; import { IFixIcon } from "../icons/IFixIt"; +import { LangChainIcon } from "../icons/LangChain"; import { MetaIcon } from "../icons/Meta"; import { MidjourneyIcon } from "../icons/Midjorney"; import { MongoDBIcon } from "../icons/MongoDB"; @@ -325,6 +325,7 @@ export const nodeIconsLucide: iconsType = { ChatOllamaModel: OllamaIcon, Faiss: MetaIcon, FaissSearch: MetaIcon, + LangChain: LangChainIcon, AzureOpenAiModel: AzureIcon, Redis: RedisIcon, RedisSearch: RedisIcon, diff --git a/src/frontend/tailwind.config.js b/src/frontend/tailwind.config.js index fd5acab36..a97e4cec0 100644 --- a/src/frontend/tailwind.config.js +++ b/src/frontend/tailwind.config.js @@ -236,6 +236,10 @@ module.exports = { ".text-align-last-right": { "text-align-last": "right", }, + ":focus-visible": { + outline: "none !important", + outlineOffset: "0px !important", + }, }); }), require("@tailwindcss/typography"),