Merge cz/mergeAll to two_edges

This commit is contained in:
ogabrielluiz 2024-06-10 11:31:02 -03:00
commit 735a7e3780
333 changed files with 6448 additions and 2498 deletions

1
.gitattributes vendored
View file

@ -32,3 +32,4 @@ Dockerfile text
*.mp4 binary *.mp4 binary
*.svg binary *.svg binary
*.csv binary *.csv binary

8
.vscode/launch.json vendored
View file

@ -3,7 +3,7 @@
"configurations": [ "configurations": [
{ {
"name": "Debug Backend", "name": "Debug Backend",
"type": "python", "type": "debugpy",
"request": "launch", "request": "launch",
"module": "uvicorn", "module": "uvicorn",
"args": [ "args": [
@ -26,7 +26,7 @@
}, },
{ {
"name": "Debug CLI", "name": "Debug CLI",
"type": "python", "type": "debugpy",
"request": "launch", "request": "launch",
"module": "langflow", "module": "langflow",
"args": [ "args": [
@ -43,7 +43,7 @@
}, },
{ {
"name": "Python: Remote Attach", "name": "Python: Remote Attach",
"type": "python", "type": "debugpy",
"request": "attach", "request": "attach",
"justMyCode": true, "justMyCode": true,
"connect": { "connect": {
@ -65,7 +65,7 @@
}, },
{ {
"name": "Python: Debug Tests", "name": "Python: Debug Tests",
"type": "python", "type": "debugpy",
"request": "launch", "request": "launch",
"program": "${file}", "program": "${file}",
"purpose": ["debug-test"], "purpose": ["debug-test"],

View file

@ -44,7 +44,8 @@ coverage:
poetry run pytest --cov \ poetry run pytest --cov \
--cov-config=.coveragerc \ --cov-config=.coveragerc \
--cov-report xml \ --cov-report xml \
--cov-report term-missing:skip-covered --cov-report term-missing:skip-covered \
--cov-report lcov:coverage/lcov-pytest.info
# allow passing arguments to pytest # allow passing arguments to pytest
tests: tests:

View file

@ -1,11 +1,13 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
# Agents # Agents
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION"> <Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
<p> <p>
We appreciate your understanding as we polish our documentation – it may contain some rough edges. Share your feedback or report issues to help us improve! 🛠️📝 We appreciate your understanding as we polish our documentation – it may
</p> contain some rough edges. Share your feedback or report issues to help us
improve! 🛠️📝
</p>
</Admonition> </Admonition>
Agents are components that use reasoning to make decisions and take actions, designed to autonomously perform tasks or provide services with some degree of agency. LLM chains can only perform hardcoded sequences of actions, while agents use LLMs to reason through which actions to take, and in which order. Agents are components that use reasoning to make decisions and take actions, designed to autonomously perform tasks or provide services with some degree of agency. LLM chains can only perform hardcoded sequences of actions, while agents use LLMs to reason through which actions to take, and in which order.
@ -87,4 +89,4 @@ The `ZeroShotAgent` uses the ReAct framework to decide which tool to use based o
**Parameters**: **Parameters**:
- **Allowed Tools:** The tools accessible to the agent. - **Allowed Tools:** The tools accessible to the agent.
- **LLM Chain:** The LLM Chain used by the agent. - **LLM Chain:** The LLM Chain used by the agent.

View file

@ -6,11 +6,11 @@ import Admonition from "@theme/Admonition";
# Chains # Chains
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION"> <Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
<p> <p>
Thank you for your patience while we enhance our documentation. It may Thank you for your patience while we enhance our documentation. It may have
have some imperfections. Share your feedback or report issues to help us some imperfections. Share your feedback or report issues to help us improve!
improve! 🛠️📝 🛠️📝
</p> </p>
</Admonition> </Admonition>
Chains, in the context of language models, refer to a series of calls made to a language model. This approach allows for using the output of one call as the input for another. Different chain types facilitate varying complexity levels, making them useful for creating pipelines and executing specific scenarios. Chains, in the context of language models, refer to a series of calls made to a language model. This approach allows for using the output of one call as the input for another. Different chain types facilitate varying complexity levels, making them useful for creating pipelines and executing specific scenarios.

View file

@ -1,4 +1,4 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
# Data # Data

View file

@ -4,113 +4,113 @@
Used to load embedding models from [Amazon Bedrock](https://aws.amazon.com/bedrock/). Used to load embedding models from [Amazon Bedrock](https://aws.amazon.com/bedrock/).
| **Parameter** | **Type** | **Description** | **Default** | | **Parameter** | **Type** | **Description** | **Default** |
|-----------------------------|-------------------|------------------------------------------------------------------------------------------------------------------------------------|-------------| | -------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `credentials_profile_name` | `str` | Name of the AWS credentials profile in ~/.aws/credentials or ~/.aws/config, which has access keys or role information. | | | `credentials_profile_name` | `str` | Name of the AWS credentials profile in ~/.aws/credentials or ~/.aws/config, which has access keys or role information. | |
| `model_id` | `str` | ID of the model to call, e.g., `amazon.titan-embed-text-v1`. This is equivalent to the `modelId` property in the `list-foundation-models` API. | | | `model_id` | `str` | ID of the model to call, e.g., `amazon.titan-embed-text-v1`. This is equivalent to the `modelId` property in the `list-foundation-models` API. | |
| `endpoint_url` | `str` | URL to set a specific service endpoint other than the default AWS endpoint. | | | `endpoint_url` | `str` | URL to set a specific service endpoint other than the default AWS endpoint. | |
| `region_name` | `str` | AWS region to use, e.g., `us-west-2`. Falls back to `AWS_DEFAULT_REGION` environment variable or region specified in ~/.aws/config if not provided. | | | `region_name` | `str` | AWS region to use, e.g., `us-west-2`. Falls back to `AWS_DEFAULT_REGION` environment variable or region specified in ~/.aws/config if not provided. | |
## Cohere Embeddings ## Cohere Embeddings
Used to load embedding models from [Cohere](https://cohere.com/). Used to load embedding models from [Cohere](https://cohere.com/).
| **Parameter** | **Type** | **Description** | **Default** | | **Parameter** | **Type** | **Description** | **Default** |
|---------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------|-----------------------| | ---------------- | -------- | ------------------------------------------------------------------------- | -------------------- |
| `cohere_api_key` | `str` | API key required to authenticate with the Cohere service. | | | `cohere_api_key` | `str` | API key required to authenticate with the Cohere service. | |
| `model` | `str` | Language model used for embedding text documents and performing queries. | `embed-english-v2.0` | | `model` | `str` | Language model used for embedding text documents and performing queries. | `embed-english-v2.0` |
| `truncate` | `bool` | Whether to truncate the input text to fit within the model's constraints. | `False` | | `truncate` | `bool` | Whether to truncate the input text to fit within the model's constraints. | `False` |
## Azure OpenAI Embeddings ## Azure OpenAI Embeddings
Generate embeddings using Azure OpenAI models. Generate embeddings using Azure OpenAI models.
| **Parameter** | **Type** | **Description** | **Default** | | **Parameter** | **Type** | **Description** | **Default** |
|---------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------|-----------------------| | ----------------- | -------- | -------------------------------------------------------------------------------------------------- | ----------- |
| `Azure Endpoint` | `str` | Your Azure endpoint, including the resource. Example: `https://example-resource.azure.openai.com/` | | | `Azure Endpoint` | `str` | Your Azure endpoint, including the resource. Example: `https://example-resource.azure.openai.com/` | |
| `Deployment Name` | `str` | The name of the deployment. | | | `Deployment Name` | `str` | The name of the deployment. | |
| `API Version` | `str` | The API version to use, options include various dates. | | | `API Version` | `str` | The API version to use, options include various dates. | |
| `API Key` | `str` | The API key to access the Azure OpenAI service. | | | `API Key` | `str` | The API key to access the Azure OpenAI service. | |
## Hugging Face API Embeddings ## Hugging Face API Embeddings
Generate embeddings using Hugging Face Inference API models. Generate embeddings using Hugging Face Inference API models.
| **Parameter** | **Type** | **Description** | **Default** | | **Parameter** | **Type** | **Description** | **Default** |
|---------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------|-----------------------| | --------------- | -------- | ----------------------------------------------------- | ------------------------ |
| `API Key` | `str` | API key for accessing the Hugging Face Inference API. | | | `API Key` | `str` | API key for accessing the Hugging Face Inference API. | |
| `API URL` | `str` | URL of the Hugging Face Inference API. | `http://localhost:8080` | | `API URL` | `str` | URL of the Hugging Face Inference API. | `http://localhost:8080` |
| `Model Name` | `str` | Name of the model to use for embeddings. | `BAAI/bge-large-en-v1.5` | | `Model Name` | `str` | Name of the model to use for embeddings. | `BAAI/bge-large-en-v1.5` |
| `Cache Folder` | `str` | Folder path to cache Hugging Face models. | | | `Cache Folder` | `str` | Folder path to cache Hugging Face models. | |
| `Encode Kwargs` | `dict` | Additional arguments for the encoding process. | | | `Encode Kwargs` | `dict` | Additional arguments for the encoding process. | |
| `Model Kwargs` | `dict` | Additional arguments for the model. | | | `Model Kwargs` | `dict` | Additional arguments for the model. | |
| `Multi Process` | `bool` | Whether to use multiple processes. | `False` | | `Multi Process` | `bool` | Whether to use multiple processes. | `False` |
## Hugging Face Embeddings ## Hugging Face Embeddings
Used to load embedding models from [HuggingFace](https://huggingface.co). Used to load embedding models from [HuggingFace](https://huggingface.co).
| **Parameter** | **Type** | **Description** | **Default** | | **Parameter** | **Type** | **Description** | **Default** |
|---------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------|-----------------------| | --------------- | -------- | ---------------------------------------------- | ----------------------------------------- |
| `Cache Folder` | `str` | Folder path to cache HuggingFace models. | | | `Cache Folder` | `str` | Folder path to cache HuggingFace models. | |
| `Encode Kwargs` | `dict` | Additional arguments for the encoding process. | | | `Encode Kwargs` | `dict` | Additional arguments for the encoding process. | |
| `Model Kwargs` | `dict` | Additional arguments for the model. | | | `Model Kwargs` | `dict` | Additional arguments for the model. | |
| `Model Name` | `str` | Name of the HuggingFace model to use. | `sentence-transformers/all-mpnet-base-v2` | | `Model Name` | `str` | Name of the HuggingFace model to use. | `sentence-transformers/all-mpnet-base-v2` |
| `Multi Process` | `bool` | Whether to use multiple processes. | `False` | | `Multi Process` | `bool` | Whether to use multiple processes. | `False` |
## OpenAI Embeddings ## OpenAI Embeddings
Used to load embedding models from [OpenAI](https://openai.com/). Used to load embedding models from [OpenAI](https://openai.com/).
| **Parameter** | **Type** | **Description** | **Default** | | **Parameter** | **Type** | **Description** | **Default** |
|-----------------------------|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| | -------------------------- | ---------------- | ------------------------------------------------ | ------------------------ |
| `OpenAI API Key` | `str` | The API key to use for accessing the OpenAI API. | | | `OpenAI API Key` | `str` | The API key to use for accessing the OpenAI API. | |
| `Default Headers` | `Dict[str, str]` | Default headers for the HTTP requests. | | | `Default Headers` | `Dict[str, str]` | Default headers for the HTTP requests. | |
| `Default Query` | `NestedDict` | Default query parameters for the HTTP requests. | | | `Default Query` | `NestedDict` | Default query parameters for the HTTP requests. | |
| `Allowed Special` | `List[str]` | Special tokens allowed for processing. | `[]` | | `Allowed Special` | `List[str]` | Special tokens allowed for processing. | `[]` |
| `Disallowed Special` | `List[str]` | Special tokens disallowed for processing. | `["all"]` | | `Disallowed Special` | `List[str]` | Special tokens disallowed for processing. | `["all"]` |
| `Chunk Size` | `int` | Chunk size for processing. | `1000` | | `Chunk Size` | `int` | Chunk size for processing. | `1000` |
| `Client` | `Any` | HTTP client for making requests. | | | `Client` | `Any` | HTTP client for making requests. | |
| `Deployment` | `str` | Deployment name for the model. | `text-embedding-3-small` | | `Deployment` | `str` | Deployment name for the model. | `text-embedding-3-small` |
| `Embedding Context Length` | `int` | Length of embedding context. | `8191` | | `Embedding Context Length` | `int` | Length of embedding context. | `8191` |
| `Max Retries` | `int` | Maximum number of retries for failed requests. | `6` | | `Max Retries` | `int` | Maximum number of retries for failed requests. | `6` |
| `Model` | `str` | Name of the model to use. | `text-embedding-3-small` | | `Model` | `str` | Name of the model to use. | `text-embedding-3-small` |
| `Model Kwargs` | `NestedDict` | Additional keyword arguments for the model. | | | `Model Kwargs` | `NestedDict` | Additional keyword arguments for the model. | |
| `OpenAI API Base` | `str` | Base URL of the OpenAI API. | | | `OpenAI API Base` | `str` | Base URL of the OpenAI API. | |
| `OpenAI API Type` | `str` | Type of the OpenAI API. | | | `OpenAI API Type` | `str` | Type of the OpenAI API. | |
| `OpenAI API Version` | `str` | Version of the OpenAI API. | | | `OpenAI API Version` | `str` | Version of the OpenAI API. | |
| `OpenAI Organization` | `str` | Organization associated with the API key. | | | `OpenAI Organization` | `str` | Organization associated with the API key. | |
| `OpenAI Proxy` | `str` | Proxy server for the requests. | | | `OpenAI Proxy` | `str` | Proxy server for the requests. | |
| `Request Timeout` | `float` | Timeout for the HTTP requests. | | | `Request Timeout` | `float` | Timeout for the HTTP requests. | |
| `Show Progress Bar` | `bool` | Whether to show a progress bar for processing. | `False` | | `Show Progress Bar` | `bool` | Whether to show a progress bar for processing. | `False` |
| `Skip Empty` | `bool` | Whether to skip empty inputs. | `False` | | `Skip Empty` | `bool` | Whether to skip empty inputs. | `False` |
| `TikToken Enable` | `bool` | Whether to enable TikToken. | `True` | | `TikToken Enable` | `bool` | Whether to enable TikToken. | `True` |
| `TikToken Model Name` | `str` | Name of the TikToken model. | | | `TikToken Model Name` | `str` | Name of the TikToken model. | |
## Ollama Embeddings ## Ollama Embeddings
Generate embeddings using Ollama models. Generate embeddings using Ollama models.
| **Parameter** | **Type** | **Description** | **Default** | | **Parameter** | **Type** | **Description** | **Default** |
|---------------------|-------------------|--------------------------------------------------------------------------------------------------------------------|---------------------------| | ------------------- | -------- | ---------------------------------------------------------------------------------------- | ------------------------ |
| `Ollama Model` | `str` | Name of the Ollama model to use. | `llama2` | | `Ollama Model` | `str` | Name of the Ollama model to use. | `llama2` |
| `Ollama Base URL` | `str` | Base URL of the Ollama API. | `http://localhost:11434` | | `Ollama Base URL` | `str` | Base URL of the Ollama API. | `http://localhost:11434` |
| `Model Temperature` | `float` | Temperature parameter for the model. Adjusts the randomness in the generated embeddings. | | | `Model Temperature` | `float` | Temperature parameter for the model. Adjusts the randomness in the generated embeddings. | |
## VertexAI Embeddings ## VertexAI Embeddings
Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) [Embeddings API](https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings). Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) [Embeddings API](https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings).
| **Parameter** | **Type** | **Description** | **Default** | | **Parameter** | **Type** | **Description** | **Default** |
|-----------------------------|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| | --------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------- |
| `credentials` | `Credentials` | The default custom credentials to use. | | | `credentials` | `Credentials` | The default custom credentials to use. | |
| `location` | `str` | The default location to use when making API calls. | `us-central1`| | `location` | `str` | The default location to use when making API calls. | `us-central1` |
| `max_output_tokens` | `int` | Token limit determines the maximum amount of text output from one prompt. | `128` | | `max_output_tokens` | `int` | Token limit determines the maximum amount of text output from one prompt. | `128` |
| `model_name` | `str` | The name of the Vertex AI large language model. | `text-bison`| | `model_name` | `str` | The name of the Vertex AI large language model. | `text-bison` |
| `project` | `str` | The default GCP project to use when making Vertex API calls. | | | `project` | `str` | The default GCP project to use when making Vertex API calls. | |
| `request_parallelism` | `int` | The amount of parallelism allowed for requests issued to VertexAI models. | `5` | | `request_parallelism` | `int` | The amount of parallelism allowed for requests issued to VertexAI models. | `5` |
| `temperature` | `float` | Tunes the degree of randomness in text generations. Should be a non-negative value. | `0` | | `temperature` | `float` | Tunes the degree of randomness in text generations. Should be a non-negative value. | `0` |
| `top_k` | `int` | How the model selects tokens for output, the next token is selected from the top `k` tokens. | `40` | | `top_k` | `int` | How the model selects tokens for output, the next token is selected from the top `k` tokens. | `40` |
| `top_p` | `float` | Tokens are selected from the most probable to least until the sum of their probabilities exceeds the top `p` value. | `0.95` | | `top_p` | `float` | Tokens are selected from the most probable to least until the sum of their probabilities exceeds the top `p` value. | `0.95` |
| `tuned_model_name` | `str` | The name of a tuned model. If provided, `model_name` is ignored. | | | `tuned_model_name` | `str` | The name of a tuned model. If provided, `model_name` is ignored. | |
| `verbose` | `bool` | This parameter controls the level of detail in the output. When set to `True`, it prints internal states of the chain to help debug. | `False` | | `verbose` | `bool` | This parameter controls the level of detail in the output. When set to `True`, it prints internal states of the chain to help debug. | `False` |

View file

@ -1,4 +1,4 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
# Experimental # Experimental
@ -29,10 +29,12 @@ This component extracts specified keys from a record.
**Parameters** **Parameters**
- **Record:** - **Record:**
- **Display Name:** Record - **Display Name:** Record
- **Info:** The record from which to extract keys. - **Info:** The record from which to extract keys.
- **Keys:** - **Keys:**
- **Display Name:** Keys - **Display Name:** Keys
- **Info:** The keys to be extracted. - **Info:** The keys to be extracted.
@ -54,6 +56,7 @@ This component turns a function running a flow into a Tool.
**Parameters** **Parameters**
- **Flow Name:** - **Flow Name:**
- **Display Name:** Flow Name - **Display Name:** Flow Name
- **Info:** Select the flow to run. - **Info:** Select the flow to run.
- **Options:** List of available flows. - **Options:** List of available flows.
@ -61,10 +64,12 @@ This component turns a function running a flow into a Tool.
- **Refresh Button:** True - **Refresh Button:** True
- **Name:** - **Name:**
- **Display Name:** Name - **Display Name:** Name
- **Description:** The tool's name. - **Description:** The tool's name.
- **Description:** - **Description:**
- **Display Name:** Description - **Display Name:** Description
- **Description:** Describes the tool. - **Description:** Describes the tool.
@ -127,10 +132,12 @@ This component generates a notification.
**Parameters** **Parameters**
- **Name:** - **Name:**
- **Display Name:** Name - **Display Name:** Name
- **Info:** The notification's name. - **Info:** The notification's name.
- **Record:** - **Record:**
- **Display Name:** Record - **Display Name:** Record
- **Info:** Optionally, a record to store in the notification. - **Info:** Optionally, a record to store in the notification.
@ -151,10 +158,12 @@ This component runs a specified flow.
**Parameters** **Parameters**
- **Input Value:** - **Input Value:**
- **Display Name:** Input Value - **Display Name:** Input Value
- **Multiline:** True - **Multiline:** True
- **Flow Name:** - **Flow Name:**
- **Display Name:** Flow Name - **Display Name:** Flow Name
- **Info:** Select the flow to run. - **Info:** Select the flow to run.
- **Options:** List of available flows. - **Options:** List of available flows.
@ -177,14 +186,17 @@ This component executes a specified runnable.
**Parameters** **Parameters**
- **Input Key:** - **Input Key:**
- **Display Name:** Input Key - **Display Name:** Input Key
- **Info:** The input key. - **Info:** The input key.
- **Inputs:** - **Inputs:**
- **Display Name:** Inputs - **Display Name:** Inputs
- **Info:** Inputs for the runnable. - **Info:** Inputs for the runnable.
- **Runnable:** - **Runnable:**
- **Display Name:** Runnable - **Display Name:** Runnable
- **Info:** The runnable to execute. - **Info:** The runnable to execute.
@ -205,14 +217,17 @@ This component executes an SQL query.
**Parameters** **Parameters**
- **Database URL:** - **Database URL:**
- **Display Name:** Database URL - **Display Name:** Database URL
- **Info:** The database's URL. - **Info:** The database's URL.
- **Include Columns:** - **Include Columns:**
- **Display Name:** Include Columns - **Display Name:** Include Columns
- **Info:** Whether to include columns in the result. - **Info:** Whether to include columns in the result.
- **Passthrough:** - **Passthrough:**
- **Display Name:** Passthrough - **Display Name:** Passthrough
- **Info:** Returns the query instead of raising an exception if an error occurs. - **Info:** Returns the query instead of raising an exception if an error occurs.
@ -233,10 +248,12 @@ This component dynamically generates a tool from a flow.
**Parameters** **Parameters**
- **Input Value:** - **Input Value:**
- **Display Name:** Input Value - **Display Name:** Input Value
- **Multiline:** True - **Multiline:** True
- **Flow Name:** - **Flow Name:**
- **Display Name:** Flow Name - **Display Name:** Flow Name
- **Info:** Select the flow to run. - **Info:** Select the flow to run.
- **Options:** List of available flows. - **Options:** List of available flows.

View file

@ -1,4 +1,4 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
# Helpers # Helpers
@ -49,9 +49,10 @@ Use this component as a template to create your custom component.
- **Parameter:** Describe the purpose of this parameter. - **Parameter:** Describe the purpose of this parameter.
<Admonition type="info" title="Info"> <Admonition type="info" title="Info">
<p> <p>
Customize the <code>build_config</code> and <code>build</code> methods according to your requirements. Customize the <code>build_config</code> and <code>build</code> methods
</p> according to your requirements.
</p>
</Admonition> </Admonition>
Learn more about creating custom components at [Custom Component](http://docs.langflow.org/components/custom). Learn more about creating custom components at [Custom Component](http://docs.langflow.org/components/custom).

View file

@ -1,11 +1,13 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
# Memories # Memories
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION"> <Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
<p> <p>
Thanks for your patience as we improve our documentation—it might have some rough edges. Share your feedback or report issues to help us enhance it! 🛠️📝 Thanks for your patience as we improve our documentation—it might have some
</p> rough edges. Share your feedback or report issues to help us enhance it!
🛠️📝
</p>
</Admonition> </Admonition>
Memory is a concept in chat-based applications that allows the system to remember previous interactions. This capability helps maintain the context of the conversation and enables the system to understand new messages in light of past messages. Memory is a concept in chat-based applications that allows the system to remember previous interactions. This capability helps maintain the context of the conversation and enables the system to understand new messages in light of past messages.
@ -24,9 +26,13 @@ This component retrieves stored messages using various filters such as sender ty
- **number_of_messages**: Specifies the number of messages to retrieve. Defaults to `5`. Determines the number of recent messages from the chat history to fetch. - **number_of_messages**: Specifies the number of messages to retrieve. Defaults to `5`. Determines the number of recent messages from the chat history to fetch.
<Admonition type="note" title="Note"> <Admonition type="note" title="Note">
<p> <p>
The component retrieves messages based on the provided criteria, including the specific file path for stored messages. If no specific criteria are provided, it returns the most recent messages up to the specified limit. This component can be used to review past interactions and analyze conversation flows. The component retrieves messages based on the provided criteria, including
</p> the specific file path for stored messages. If no specific criteria are
provided, it returns the most recent messages up to the specified limit.
This component can be used to review past interactions and analyze
conversation flows.
</p>
</Admonition> </Admonition>
### ConversationBufferMemory ### ConversationBufferMemory
@ -84,7 +90,8 @@ The `ConversationKGMemory` utilizes a knowledge graph to enhance memory capabili
- **memory_key**: Specifies the prompt variable name where the memory stores and retrieves chat messages. Defaults to `chat_history`. - **memory_key**: Specifies the prompt variable name where the memory stores and retrieves chat messages. Defaults to `chat_history`.
- **output_key**: Identifies the key under which the generated response - **output_key**: Identifies the key under which the generated response
is stored, enabling retrieval using this key. is stored, enabling retrieval using this key.
- **return_messages**: Controls whether the history is returned as a string or as a list of messages. Defaults to `False`. - **return_messages**: Controls whether the history is returned as a string or as a list of messages. Defaults to `False`.
--- ---
@ -124,4 +131,4 @@ The `VectorRetrieverMemory` retrieves vectors based on queries, facilitating vec
- **Retriever**: The tool used to fetch documents. - **Retriever**: The tool used to fetch documents.
- **input_key**: Identifies where input messages are stored in the memory object, facilitating their retrieval and manipulation. - **input_key**: Identifies where input messages are stored in the memory object, facilitating their retrieval and manipulation.
- **memory_key**: Specifies the prompt variable name where the memory stores and retrieves chat messages. Defaults to `chat_history`. - **memory_key**: Specifies the prompt variable name where the memory stores and retrieves chat messages. Defaults to `chat_history`.
- **return_messages**: Controls whether the history is returned as a string or as a list of messages. Defaults to `False`. - **return_messages**: Controls whether the history is returned as a string or as a list of messages. Defaults to `False`.

View file

@ -1,11 +1,13 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
# Large Language Models (LLMs) # Large Language Models (LLMs)
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION"> <Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
<p> <p>
Thank you for your patience as we refine our documentation. You might encounter some inconsistencies. Please help us improve by sharing your feedback or reporting any issues! 🛠️📝 Thank you for your patience as we refine our documentation. You might
</p> encounter some inconsistencies. Please help us improve by sharing your
feedback or reporting any issues! 🛠️📝
</p>
</Admonition> </Admonition>
A Large Language Model (LLM) is a foundational component of Langflow. It provides a uniform interface for interacting with LLMs from various providers, including OpenAI, Cohere, and HuggingFace. Langflow extensively uses LLMs across its chains and agents, employing them to generate text based on specific prompts or inputs. A Large Language Model (LLM) is a foundational component of Langflow. It provides a uniform interface for interacting with LLMs from various providers, including OpenAI, Cohere, and HuggingFace. Langflow extensively uses LLMs across its chains and agents, employing them to generate text based on specific prompts or inputs.
@ -37,7 +39,9 @@ This is a wrapper for Anthropic's large language model designed for chat-based i
`CTransformers` provides access to Transformer models implemented in C/C++ using the [GGML](https://github.com/ggerganov/ggml) library. `CTransformers` provides access to Transformer models implemented in C/C++ using the [GGML](https://github.com/ggerganov/ggml) library.
<Admonition type="info"> <Admonition type="info">
Ensure the `ctransformers` Python package is installed. Discover more about installation, supported models, and usage [here](https://github.com/marella/ctransformers). Ensure the `ctransformers` Python package is installed. Discover more about
installation, supported models, and usage
[here](https://github.com/marella/ctransformers).
</Admonition> </Admonition>
- **config:** This configuration is for the Transformer models. Check the default settings and possible configurations at [config](https://github.com/marella/ctransformers#config). - **config:** This configuration is for the Transformer models. Check the default settings and possible configurations at [config](https://github.com/marella/ctransformers#config).
@ -128,7 +132,8 @@ This component integrates with [Google Vertex AI](https://cloud.google.com/verte
- **credentials**: Custom - **credentials**: Custom
credentials used for API interactions. credentials used for API interactions.
- **location**: The default location for API calls, defaulting to `us-central1`. - **location**: The default location for API calls, defaulting to `us-central1`.
- **max_output_tokens**: Limits the output tokens per prompt, defaulting to `128`. - **max_output_tokens**: Limits the output tokens per prompt, defaulting to `128`.
- **model_name**: The name of the Vertex AI model in use, defaulting to `text-bison`. - **model_name**: The name of the Vertex AI model in use, defaulting to `text-bison`.
@ -140,4 +145,4 @@ This component integrates with [Google Vertex AI](https://cloud.google.com/verte
- **tuned_model_name**: Specifies a tuned model name, which overrides the default model name if provided. - **tuned_model_name**: Specifies a tuned model name, which overrides the default model name if provided.
- **verbose**: Controls the output verbosity to assist in debugging and understanding the operational details, defaulting to `False`. - **verbose**: Controls the output verbosity to assist in debugging and understanding the operational details, defaulting to `False`.
--- ---

View file

@ -1,11 +1,13 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
# Retrievers # Retrievers
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION"> <Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
<p> <p>
We appreciate your patience as we enhance our documentation. It may have some imperfections. Please share your feedback or report issues to help us improve. 🛠️📝 We appreciate your patience as we enhance our documentation. It may have
</p> some imperfections. Please share your feedback or report issues to help us
improve. 🛠️📝
</p>
</Admonition> </Admonition>
A retriever is an interface that returns documents in response to an unstructured query. It's broader than a vector store because it doesn't need to store documents; it only needs to retrieve them. A retriever is an interface that returns documents in response to an unstructured query. It's broader than a vector store because it doesn't need to store documents; it only needs to retrieve them.

View file

@ -1,9 +1,11 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
# Toolkits # Toolkits
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION"> <Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
<p> <p>
We appreciate your understanding as we polish our documentation – it may contain some rough edges. Share your feedback or report issues to help us improve! 🛠️📝 We appreciate your understanding as we polish our documentation - it may
</p> contain some rough edges. Share your feedback or report issues to help us
</Admonition> improve! 🛠️📝
</p>
</Admonition>

View file

@ -1,11 +1,13 @@
import Admonition from '@theme/Admonition'; import Admonition from "@theme/Admonition";
# Tools # Tools
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION"> <Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
<p> <p>
Thanks for your patience as we refine our documentation. It might have some rough edges currently. Please share your feedback or report issues to help us enhance it! 🛠️📝 Thanks for your patience as we refine our documentation. It might have some
</p> rough edges currently. Please share your feedback or report issues to help
us enhance it! 🛠️📝
</p>
</Admonition> </Admonition>
### SearchApi ### SearchApi

View file

@ -3,9 +3,9 @@ import Admonition from "@theme/Admonition";
# Utilities # Utilities
<Admonition type="caution" icon="🚧" title="Zone Under Construction"> <Admonition type="caution" icon="🚧" title="Zone Under Construction">
We appreciate your understanding as we polish our documentation—it may We appreciate your understanding as we polish our documentation—it may contain
contain some rough edges. Share your feedback or report issues to help us some rough edges. Share your feedback or report issues to help us improve!
improve! 🛠️📝 🛠️📝
</Admonition> </Admonition>
Utilities are a set of actions that can be used to perform common tasks in a flow. They are available in the **Utilities** section in the sidebar. Utilities are a set of actions that can be used to perform common tasks in a flow. They are available in the **Utilities** section in the sidebar.
@ -86,7 +86,11 @@ Generates a unique identifier (UUID) for each instance it is invoked, providing
- Returns a unique identifier (UUID) as a string. This UUID is generated using Python's `uuid` module, ensuring that each identifier is unique and can be used as a reliable reference in your application. - Returns a unique identifier (UUID) as a string. This UUID is generated using Python's `uuid` module, ensuring that each identifier is unique and can be used as a reliable reference in your application.
<Admonition type="note" title="Note"> <Admonition type="note" title="Note">
The Unique ID Generator is crucial for scenarios requiring distinct identifiers, such as session management, transaction tracking, or any context where different instances or entities must be uniquely identified. The generated UUID is provided as a hexadecimal string, offering a high level of uniqueness and security for identification purposes. The Unique ID Generator is crucial for scenarios requiring distinct
identifiers, such as session management, transaction tracking, or any context
where different instances or entities must be uniquely identified. The
generated UUID is provided as a hexadecimal string, offering a high level of
uniqueness and security for identification purposes.
</Admonition> </Admonition>
For additional information and examples, please consult the [Langflow Components Custom Documentation](http://docs.langflow.org/components/custom). For additional information and examples, please consult the [Langflow Components Custom Documentation](http://docs.langflow.org/components/custom).

View file

@ -4,7 +4,7 @@ You can run Langflow in `--backend-only` mode to expose your Langflow app as an
Start langflow in backend-only mode with `python3 -m langflow run --backend-only`. Start langflow in backend-only mode with `python3 -m langflow run --backend-only`.
The terminal prints ` Welcome to ⛓ Langflow `, and a blank window opens at `http://127.0.0.1:7864/all`. The terminal prints `Welcome to ⛓ Langflow`, and a blank window opens at `http://127.0.0.1:7864/all`.
Langflow will now serve requests to its API without the frontend running. Langflow will now serve requests to its API without the frontend running.
## Prerequisites ## Prerequisites
@ -42,7 +42,7 @@ Note the flow ID of `ef7e0554-69e5-4e3e-ab29-ee83bcd8d9ef`. You can find this ID
1. Stop Langflow with Ctrl+C. 1. Stop Langflow with Ctrl+C.
2. Start langflow in backend-only mode with `python3 -m langflow run --backend-only`. 2. Start langflow in backend-only mode with `python3 -m langflow run --backend-only`.
The terminal prints ` Welcome to ⛓ Langflow `, and a blank window opens at `http://127.0.0.1:7864/all`. The terminal prints `Welcome to ⛓ Langflow`, and a blank window opens at `http://127.0.0.1:7864/all`.
Langflow will now serve requests to its API. Langflow will now serve requests to its API.
3. Run the curl code you copied from the UI. 3. Run the curl code you copied from the UI.
You should get a result like this: You should get a result like this:

File diff suppressed because it is too large Load diff

88
poetry.lock generated
View file

@ -471,17 +471,17 @@ files = [
[[package]] [[package]]
name = "boto3" name = "boto3"
version = "1.34.121" version = "1.34.122"
description = "The AWS SDK for Python" description = "The AWS SDK for Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "boto3-1.34.121-py3-none-any.whl", hash = "sha256:4e79e400d6d44b4eee5deda6ac0ecd08a3f5a30c45a0d30712795cdc4459fd79"}, {file = "boto3-1.34.122-py3-none-any.whl", hash = "sha256:b2d7400ff84fa547e53b3d9acfa3c95d65d45b5886ba1ede1f7df4768d1cc0b1"},
{file = "boto3-1.34.121.tar.gz", hash = "sha256:ec89f3e0b0dc959c418df29e14d3748c0b05ab7acf7c0b90c839e9f340a659fa"}, {file = "boto3-1.34.122.tar.gz", hash = "sha256:56840d8ce91654d182f1c113f0791fa2113c3aa43230c50b4481f235348a6037"},
] ]
[package.dependencies] [package.dependencies]
botocore = ">=1.34.121,<1.35.0" botocore = ">=1.34.122,<1.35.0"
jmespath = ">=0.7.1,<2.0.0" jmespath = ">=0.7.1,<2.0.0"
s3transfer = ">=0.10.0,<0.11.0" s3transfer = ">=0.10.0,<0.11.0"
@ -490,13 +490,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
[[package]] [[package]]
name = "botocore" name = "botocore"
version = "1.34.121" version = "1.34.122"
description = "Low-level, data-driven core of boto 3." description = "Low-level, data-driven core of boto 3."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "botocore-1.34.121-py3-none-any.whl", hash = "sha256:25b05c7646a9f240cde1c8f839552a43f27e71e15c42600275dea93e219f7dd9"}, {file = "botocore-1.34.122-py3-none-any.whl", hash = "sha256:6d75df3af831b62f0c7baa109728d987e0a8d34bfadf0476eb32e2f29a079a36"},
{file = "botocore-1.34.121.tar.gz", hash = "sha256:1a8f94b917c47dfd84a0b531ab607dc53570efb0d073d8686600f2d2be985323"}, {file = "botocore-1.34.122.tar.gz", hash = "sha256:9374e16a36f1062c3e27816e8599b53eba99315dfac71cc84fc3aee3f5d3cbe3"},
] ]
[package.dependencies] [package.dependencies]
@ -1450,13 +1450,13 @@ tests = ["pytest"]
[[package]] [[package]]
name = "dataclasses-json" name = "dataclasses-json"
version = "0.6.6" version = "0.6.7"
description = "Easily serialize dataclasses to and from JSON." description = "Easily serialize dataclasses to and from JSON."
optional = false optional = false
python-versions = "<4.0,>=3.7" python-versions = "<4.0,>=3.7"
files = [ files = [
{file = "dataclasses_json-0.6.6-py3-none-any.whl", hash = "sha256:e54c5c87497741ad454070ba0ed411523d46beb5da102e221efb873801b0ba85"}, {file = "dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a"},
{file = "dataclasses_json-0.6.6.tar.gz", hash = "sha256:0c09827d26fffda27f1be2fed7a7a01a29c5ddcd2eb6393ad5ebf9d77e9deae8"}, {file = "dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0"},
] ]
[package.dependencies] [package.dependencies]
@ -1590,6 +1590,23 @@ files = [
[package.dependencies] [package.dependencies]
packaging = "*" packaging = "*"
[[package]]
name = "dictdiffer"
version = "0.9.0"
description = "Dictdiffer is a library that helps you to diff and patch dictionaries."
optional = false
python-versions = "*"
files = [
{file = "dictdiffer-0.9.0-py2.py3-none-any.whl", hash = "sha256:442bfc693cfcadaf46674575d2eba1c53b42f5e404218ca2c2ff549f2df56595"},
{file = "dictdiffer-0.9.0.tar.gz", hash = "sha256:17bacf5fbfe613ccf1b6d512bd766e6b21fb798822a133aa86098b8ac9997578"},
]
[package.extras]
all = ["Sphinx (>=3)", "check-manifest (>=0.42)", "mock (>=1.3.0)", "numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "sphinx-rtd-theme (>=0.2)", "tox (>=3.7.0)"]
docs = ["Sphinx (>=3)", "sphinx-rtd-theme (>=0.2)"]
numpy = ["numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)"]
tests = ["check-manifest (>=0.42)", "mock (>=1.3.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "tox (>=3.7.0)"]
[[package]] [[package]]
name = "dill" name = "dill"
version = "0.3.7" version = "0.3.7"
@ -2392,8 +2409,8 @@ files = [
[package.dependencies] [package.dependencies]
cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""} cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""}
greenlet = [ greenlet = [
{version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""},
{version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""}, {version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""},
{version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""},
] ]
"zope.event" = "*" "zope.event" = "*"
"zope.interface" = "*" "zope.interface" = "*"
@ -2552,12 +2569,12 @@ files = [
google-auth = ">=2.14.1,<3.0.dev0" google-auth = ">=2.14.1,<3.0.dev0"
googleapis-common-protos = ">=1.56.2,<2.0.dev0" googleapis-common-protos = ">=1.56.2,<2.0.dev0"
grpcio = [ grpcio = [
{version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""},
{version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""},
{version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""},
] ]
grpcio-status = [ grpcio-status = [
{version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""},
{version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""},
{version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""},
] ]
proto-plus = ">=1.22.3,<2.0.0dev" proto-plus = ">=1.22.3,<2.0.0dev"
protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0"
@ -2626,13 +2643,13 @@ httplib2 = ">=0.19.0"
[[package]] [[package]]
name = "google-cloud-aiplatform" name = "google-cloud-aiplatform"
version = "1.54.0" version = "1.54.1"
description = "Vertex AI API client library" description = "Vertex AI API client library"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "google-cloud-aiplatform-1.54.0.tar.gz", hash = "sha256:6f5187d35a32951028465804fbb42b478362bf41e2b634ddd22b150299f6e1d8"}, {file = "google-cloud-aiplatform-1.54.1.tar.gz", hash = "sha256:01c231961cc1a1a3b049ea3ef71fb11e77b2d56d632d020ce09e419b27ff77f2"},
{file = "google_cloud_aiplatform-1.54.0-py2.py3-none-any.whl", hash = "sha256:7b3ed849b9fb59a01bd6f44444ccbb7d18495b867a26f913542f6b2d4c3de252"}, {file = "google_cloud_aiplatform-1.54.1-py2.py3-none-any.whl", hash = "sha256:43f70fcd572f15317d769e5a0e04cfb7c0e259ead3fe581d2fba4f203ace5617"},
] ]
[package.dependencies] [package.dependencies]
@ -4323,13 +4340,13 @@ extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"]
[[package]] [[package]]
name = "langchainhub" name = "langchainhub"
version = "0.1.17" version = "0.1.18"
description = "The LangChain Hub API client" description = "The LangChain Hub API client"
optional = false optional = false
python-versions = "<4.0,>=3.8.1" python-versions = "<4.0,>=3.8.1"
files = [ files = [
{file = "langchainhub-0.1.17-py3-none-any.whl", hash = "sha256:4c609b3948252c71670f0d98f73413b515cfd2f6701a7b40ce959203e6133e04"}, {file = "langchainhub-0.1.18-py3-none-any.whl", hash = "sha256:11501f15e7f34715ecc8892587daa35c6f2a3005e1f2926c9bcabd31fc2c100c"},
{file = "langchainhub-0.1.17.tar.gz", hash = "sha256:af7df0cb1cebc7a6e0864e8632ae48ecad39ed96568f699c78657b9d04e50b46"}, {file = "langchainhub-0.1.18.tar.gz", hash = "sha256:f2d0d8bf3abe4ca5e70511d8220bdc9ccea28d5267bcfd0e5ef9c53bd5bd3bad"},
] ]
[package.dependencies] [package.dependencies]
@ -4435,13 +4452,13 @@ requests = ">=2,<3"
[[package]] [[package]]
name = "litellm" name = "litellm"
version = "1.40.4" version = "1.40.7"
description = "Library to easily interface with LLM API providers" description = "Library to easily interface with LLM API providers"
optional = false optional = false
python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8"
files = [ files = [
{file = "litellm-1.40.4-py3-none-any.whl", hash = "sha256:b3b8e4401f717c3a18595446bfdb80fc6bb74974aac4eae537fb7b3be37fbf9e"}, {file = "litellm-1.40.7-py3-none-any.whl", hash = "sha256:c98dd8733e632aba16f14bf82e56f7159222097a6d085b242a3140b5d3e7baa4"},
{file = "litellm-1.40.4.tar.gz", hash = "sha256:3edaa1189742afd7c7df2b122f77373d47154a8fb6df6187ff5875e188baa3e1"}, {file = "litellm-1.40.7.tar.gz", hash = "sha256:557bb19e8e484d0dfe8e4eaa9ccefc888617852988a46d6e7adc41585a2c0600"},
] ]
[package.dependencies] [package.dependencies]
@ -4483,13 +4500,13 @@ test = ["httpx (>=0.24.1)", "pytest (>=7.4.0)", "scipy (>=1.10)"]
[[package]] [[package]]
name = "locust" name = "locust"
version = "2.28.0" version = "2.29.0"
description = "Developer-friendly load testing framework" description = "Developer-friendly load testing framework"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
files = [ files = [
{file = "locust-2.28.0-py3-none-any.whl", hash = "sha256:766be879db030c0118e7d9fca712f3538c4e628bdebf59468fa1c6c2fab217d3"}, {file = "locust-2.29.0-py3-none-any.whl", hash = "sha256:aa9d94d3604ed9f2aab3248460d91e55d3de980a821dffdf8658b439b049d03f"},
{file = "locust-2.28.0.tar.gz", hash = "sha256:260557eec866f7e34a767b6c916b5b278167562a280480aadb88f43d962fbdeb"}, {file = "locust-2.29.0.tar.gz", hash = "sha256:649c99ce49d00720a3084c0109547035ad9021222835386599a8b545d31ebe51"},
] ]
[package.dependencies] [package.dependencies]
@ -4503,7 +4520,10 @@ msgpack = ">=1.0.0"
psutil = ">=5.9.1" psutil = ">=5.9.1"
pywin32 = {version = "*", markers = "platform_system == \"Windows\""} pywin32 = {version = "*", markers = "platform_system == \"Windows\""}
pyzmq = ">=25.0.0" pyzmq = ">=25.0.0"
requests = ">=2.26.0" requests = [
{version = ">=2.32.2", markers = "python_version > \"3.11\""},
{version = ">=2.26.0", markers = "python_version <= \"3.11\""},
]
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
Werkzeug = ">=2.0.0" Werkzeug = ">=2.0.0"
@ -5599,13 +5619,13 @@ sympy = "*"
[[package]] [[package]]
name = "openai" name = "openai"
version = "1.32.0" version = "1.33.0"
description = "The official Python library for the openai API" description = "The official Python library for the openai API"
optional = false optional = false
python-versions = ">=3.7.1" python-versions = ">=3.7.1"
files = [ files = [
{file = "openai-1.32.0-py3-none-any.whl", hash = "sha256:953d57669f309002044fd2f678aba9f07a43256d74b3b00cd04afb5b185568ea"}, {file = "openai-1.33.0-py3-none-any.whl", hash = "sha256:621163b56570897ab8389d187f686a53d4771fd6ce95d481c0a9611fe8bc4229"},
{file = "openai-1.32.0.tar.gz", hash = "sha256:a6df15a7ab9344b1bc2bc8d83639f68b7a7e2453c0f5e50c1666547eee86f0bd"}, {file = "openai-1.33.0.tar.gz", hash = "sha256:1169211a7b326ecbc821cafb427c29bfd0871f9a3e0947dd9e51acb3b0f1df78"},
] ]
[package.dependencies] [package.dependencies]
@ -5931,9 +5951,9 @@ files = [
[package.dependencies] [package.dependencies]
numpy = [ numpy = [
{version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""},
{version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""},
{version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""},
{version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""},
] ]
python-dateutil = ">=2.8.2" python-dateutil = ">=2.8.2"
pytz = ">=2020.1" pytz = ">=2020.1"
@ -9068,13 +9088,13 @@ files = [
[[package]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.12.1" version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+" description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
] ]
[[package]] [[package]]
@ -10081,4 +10101,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.10,<3.13" python-versions = ">=3.10,<3.13"
content-hash = "d87bda272f67450430630924263690c2ae62416d0b240e029baaa8da07154bec" content-hash = "0ee3f3bef82d57be2ab4ae7b70215ebca67b5bd5223e6a9322ee1837516a3cc6"

View file

@ -116,6 +116,7 @@ pytest-asyncio = "^0.23.0"
pytest-profiling = "^1.7.0" pytest-profiling = "^1.7.0"
pre-commit = "^3.7.0" pre-commit = "^3.7.0"
vulture = "^2.11" vulture = "^2.11"
dictdiffer = "^0.9.0"
[tool.poetry.extras] [tool.poetry.extras]
deploy = ["celery", "redis", "flower"] deploy = ["celery", "redis", "flower"]

View file

@ -86,6 +86,10 @@ def update_frontend_node_with_template_values(frontend_node, raw_frontend_node):
update_template_values(frontend_node["template"], raw_frontend_node["template"]) update_template_values(frontend_node["template"], raw_frontend_node["template"])
old_code = raw_frontend_node["template"]["code"]["value"]
new_code = frontend_node["template"]["code"]["value"]
frontend_node["edited"] = old_code != new_code
return frontend_node return frontend_node
@ -204,16 +208,18 @@ def format_elapsed_time(elapsed_time: float) -> str:
return f"{minutes} {minutes_unit}, {seconds} {seconds_unit}" return f"{minutes} {minutes_unit}, {seconds} {seconds_unit}"
async def build_and_cache_graph_from_db( async def build_and_cache_graph_from_db(flow_id: str, session: Session, chat_service: "ChatService"):
flow_id: str,
session: Session,
chat_service: "ChatService",
):
"""Build and cache the graph.""" """Build and cache the graph."""
flow: Optional[Flow] = session.get(Flow, flow_id) flow: Optional[Flow] = session.get(Flow, flow_id)
if not flow or not flow.data: if not flow or not flow.data:
raise ValueError("Invalid flow ID") raise ValueError("Invalid flow ID")
graph = Graph.from_payload(flow.data, flow_id) graph = Graph.from_payload(flow.data, flow_id)
for vertex_id in graph._has_session_id_vertices:
vertex = graph.get_vertex(vertex_id)
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})
await chat_service.set_cache(flow_id, graph) await chat_service.set_cache(flow_id, graph)
return graph return graph
@ -317,3 +323,4 @@ def parse_exception(exc):
if hasattr(exc, "body"): if hasattr(exc, "body"):
return exc.body["message"] return exc.body["message"]
return str(exc) return str(exc)
return str(exc)

View file

@ -22,6 +22,7 @@ from langflow.api.v1.schemas import (
VertexBuildResponse, VertexBuildResponse,
VerticesOrderResponse, VerticesOrderResponse,
) )
from langflow.schema.schema import Log
from langflow.services.auth.utils import get_current_active_user from langflow.services.auth.utils import get_current_active_user
from langflow.services.chat.service import ChatService from langflow.services.chat.service import ChatService
from langflow.services.deps import get_chat_service, get_session, get_session_service from langflow.services.deps import get_chat_service, get_session, get_session_service
@ -123,6 +124,7 @@ async def build_vertex(
vertex_id: str, vertex_id: str,
background_tasks: BackgroundTasks, background_tasks: BackgroundTasks,
inputs: Annotated[Optional[InputValueRequest], Body(embed=True)] = None, inputs: Annotated[Optional[InputValueRequest], Body(embed=True)] = None,
files: Optional[list[str]] = None,
chat_service: "ChatService" = Depends(get_chat_service), chat_service: "ChatService" = Depends(get_chat_service),
current_user=Depends(get_current_active_user), current_user=Depends(get_current_active_user),
): ):
@ -159,6 +161,7 @@ async def build_vertex(
else: else:
graph = cache.get("result") graph = cache.get("result")
vertex = graph.get_vertex(vertex_id) vertex = graph.get_vertex(vertex_id)
try: try:
lock = chat_service._cache_locks[flow_id_str] lock = chat_service._cache_locks[flow_id_str]
( (
@ -175,19 +178,25 @@ async def build_vertex(
vertex_id=vertex_id, vertex_id=vertex_id,
user_id=current_user.id, user_id=current_user.id,
inputs_dict=inputs.model_dump() if inputs else {}, inputs_dict=inputs.model_dump() if inputs else {},
files=files,
) )
log_obj = Log(message=vertex.artifacts_raw, type=vertex.artifacts_type)
result_data_response = ResultDataResponse(**result_dict.model_dump()) result_data_response = ResultDataResponse(**result_dict.model_dump())
except Exception as exc: except Exception as exc:
logger.exception(f"Error building vertex: {exc}") logger.exception(f"Error building vertex: {exc}")
params = format_exception_message(exc) params = format_exception_message(exc)
valid = False valid = False
log_obj = Log(message=params, type="error")
result_data_response = ResultDataResponse(results={}) result_data_response = ResultDataResponse(results={})
artifacts = {} artifacts = {}
# If there's an error building the vertex # If there's an error building the vertex
# we need to clear the cache # we need to clear the cache
await chat_service.clear_cache(flow_id_str) await chat_service.clear_cache(flow_id_str)
result_data_response.message = artifacts
result_data_response.logs.append(log_obj)
# Log the vertex build # Log the vertex build
if not vertex.will_stream: if not vertex.will_stream:
background_tasks.add_task( background_tasks.add_task(

View file

@ -2,6 +2,7 @@ import hashlib
from http import HTTPStatus from http import HTTPStatus
from io import BytesIO from io import BytesIO
from uuid import UUID from uuid import UUID
from pathlib import Path
from fastapi import APIRouter, Depends, HTTPException, UploadFile from fastapi import APIRouter, Depends, HTTPException, UploadFile
from fastapi.responses import StreamingResponse from fastapi.responses import StreamingResponse
@ -99,6 +100,46 @@ async def download_image(file_name: str, flow_id: UUID, storage_service: Storage
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@router.get("/profile_pictures/{folder_name}/{file_name}")
async def download_profile_picture(
folder_name: str,
file_name: str,
storage_service: StorageService = Depends(get_storage_service),
):
try:
extension = file_name.split(".")[-1]
config_dir = get_storage_service().settings_service.settings.config_dir
config_path = Path(config_dir)
folder_path = config_path / "profile_pictures" / folder_name
content_type = build_content_type_from_extension(extension)
file_content = await storage_service.get_file(flow_id=folder_path, file_name=file_name)
return StreamingResponse(BytesIO(file_content), media_type=content_type)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/profile_pictures/list")
async def list_profile_pictures(storage_service: StorageService = Depends(get_storage_service)):
try:
config_dir = get_storage_service().settings_service.settings.config_dir
config_path = Path(config_dir)
people_path = config_path / "profile_pictures/People"
space_path = config_path / "profile_pictures/Space"
people = await storage_service.list_files(flow_id=people_path)
space = await storage_service.list_files(flow_id=space_path)
files = [Path("People") / i for i in people]
files += [Path("Space") / i for i in space]
return {"files": files}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/list/{flow_id}") @router.get("/list/{flow_id}")
async def list_files( async def list_files(
flow_id: UUID = Depends(get_flow_id), storage_service: StorageService = Depends(get_storage_service) flow_id: UUID = Depends(get_flow_id), storage_service: StorageService = Depends(get_storage_service)

View file

@ -1,5 +1,7 @@
from typing import List from typing import List
from langflow.helpers.flow import generate_unique_flow_name
from langflow.helpers.folders import generate_unique_folder_name
import orjson import orjson
from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status
from sqlalchemy import or_, update from sqlalchemy import or_, update
@ -203,16 +205,9 @@ async def upload_file(
if not data: if not data:
raise HTTPException(status_code=400, detail="No flows found in the file") raise HTTPException(status_code=400, detail="No flows found in the file")
folder_results = session.exec( folder_name = generate_unique_folder_name(data["folder_name"], current_user.id, session)
select(Folder).where(
Folder.name == data["folder_name"],
Folder.user_id == current_user.id,
)
)
existing_folder_names = [folder.name for folder in folder_results]
if existing_folder_names: data["folder_name"] = folder_name
data["folder_name"] = f"{data['folder_name']} ({len(existing_folder_names) + 1})"
folder = FolderCreate(name=data["folder_name"], description=data["folder_description"]) folder = FolderCreate(name=data["folder_name"], description=data["folder_description"])
@ -232,6 +227,8 @@ async def upload_file(
raise HTTPException(status_code=400, detail="No flows found in the data") raise HTTPException(status_code=400, detail="No flows found in the data")
# Now we set the user_id for all flows # Now we set the user_id for all flows
for flow in flow_list.flows: for flow in flow_list.flows:
flow_name = generate_unique_flow_name(flow.name, current_user.id, session)
flow.name = flow_name
flow.user_id = current_user.id flow.user_id = current_user.id
flow.folder_id = new_folder.id flow.folder_id = new_folder.id

View file

@ -1,4 +1,6 @@
from typing import List, Optional from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query from fastapi import APIRouter, Depends, HTTPException, Query
from langflow.services.deps import get_monitor_service from langflow.services.deps import get_monitor_service
@ -79,7 +81,7 @@ async def delete_messages(
@router.post("/messages/{message_id}", response_model=MessageModelResponse) @router.post("/messages/{message_id}", response_model=MessageModelResponse)
async def update_message( async def update_message(
message_id: str, message_id: int,
message: MessageModelRequest, message: MessageModelRequest,
monitor_service: MonitorService = Depends(get_monitor_service), monitor_service: MonitorService = Depends(get_monitor_service),
): ):
@ -117,6 +119,22 @@ async def get_transactions(
dicts = monitor_service.get_transactions( dicts = monitor_service.get_transactions(
source=source, target=target, status=status, order_by=order_by, flow_id=flow_id source=source, target=target, status=status, order_by=order_by, flow_id=flow_id
) )
return [TransactionModelResponse(**d) for d in dicts] result = []
for d in dicts:
d = TransactionModelResponse(
index=d["index"],
timestamp=d["timestamp"],
vertex_id=d["vertex_id"],
inputs=d["inputs"],
outputs=d["outputs"],
status=d["status"],
error=d["error"],
flow_id=d["flow_id"],
source=d["vertex_id"],
target=d["target_id"],
)
result.append(d)
return result
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e))

View file

@ -9,7 +9,7 @@ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_serial
from langflow.graph.schema import RunOutputs from langflow.graph.schema import RunOutputs
from langflow.schema import dotdict from langflow.schema import dotdict
from langflow.schema.graph import Tweaks from langflow.schema.graph import Tweaks
from langflow.schema.schema import InputType, OutputType from langflow.schema.schema import InputType, Log, OutputType
from langflow.services.database.models.api_key.model import ApiKeyRead from langflow.services.database.models.api_key.model import ApiKeyRead
from langflow.services.database.models.base import orjson_dumps from langflow.services.database.models.base import orjson_dumps
from langflow.services.database.models.flow import FlowCreate, FlowRead from langflow.services.database.models.flow import FlowCreate, FlowRead
@ -245,6 +245,8 @@ class VerticesOrderResponse(BaseModel):
class ResultDataResponse(BaseModel): class ResultDataResponse(BaseModel):
results: Optional[Any] = Field(default_factory=dict) results: Optional[Any] = Field(default_factory=dict)
logs: List[Log | None] = Field(default_factory=list)
message: Optional[Any] = Field(default_factory=dict)
artifacts: Optional[Any] = Field(default_factory=dict) artifacts: Optional[Any] = Field(default_factory=dict)
timedelta: Optional[float] = None timedelta: Optional[float] = None
duration: Optional[str] = None duration: Optional[str] = None

View file

@ -7,7 +7,7 @@ from langchain_core.runnables import Runnable
from langflow.base.agents.utils import get_agents_list, records_to_messages from langflow.base.agents.utils import get_agents_list, records_to_messages
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import Text, Tool from langflow.field_typing import Text, Tool
from langflow.schema.schema import Record from langflow.schema import Record
class LCAgentComponent(CustomComponent): class LCAgentComponent(CustomComponent):

View file

@ -13,7 +13,7 @@ from langchain_core.prompts import BasePromptTemplate, ChatPromptTemplate
from langchain_core.tools import BaseTool from langchain_core.tools import BaseTool
from pydantic import BaseModel from pydantic import BaseModel
from langflow.schema.schema import Record from langflow.schema import Record
from .default_prompts import XML_AGENT_PROMPT from .default_prompts import XML_AGENT_PROMPT

View file

@ -7,9 +7,11 @@ Constants:
- FIELD_FORMAT_ATTRIBUTES: A list of attributes used for formatting fields. - FIELD_FORMAT_ATTRIBUTES: A list of attributes used for formatting fields.
""" """
import orjson
STREAM_INFO_TEXT = "Stream the response from the model. Streaming works only in Chat." STREAM_INFO_TEXT = "Stream the response from the model. Streaming works only in Chat."
NODE_FORMAT_ATTRIBUTES = ["beta", "icon", "display_name", "description"] NODE_FORMAT_ATTRIBUTES = ["beta", "icon", "display_name", "description", "output_types"]
FIELD_FORMAT_ATTRIBUTES = [ FIELD_FORMAT_ATTRIBUTES = [
@ -28,3 +30,5 @@ FIELD_FORMAT_ATTRIBUTES = [
"options", "options",
"advanced", "advanced",
] ]
ORJSON_OPTIONS = orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS | orjson.OPT_OMIT_MICROSECONDS

View file

@ -16,7 +16,7 @@ from collections import OrderedDict, namedtuple
from http.cookies import SimpleCookie from http.cookies import SimpleCookie
ParsedArgs = namedtuple( ParsedArgs = namedtuple(
"ParsedContext", "ParsedArgs",
[ [
"command", "command",
"url", "url",
@ -64,21 +64,20 @@ def parse_curl_command(curl_command):
"cookies": {}, "cookies": {},
} }
args = args_template.copy() args = args_template.copy()
method_on_curl = None
i = 0 i = 0
while i < len(tokens): while i < len(tokens):
token = tokens[i] token = tokens[i]
if token == "-X": if token == "-X":
i += 1 i += 1
args["method"] = tokens[i].lower() args["method"] = tokens[i].lower()
method_on_curl = tokens[i].lower()
elif token in ("-d", "--data"): elif token in ("-d", "--data"):
i += 1 i += 1
args["data"] = tokens[i] args["data"] = tokens[i]
args["method"] = "post"
elif token in ("-b", "--data-binary", "--data-raw"): elif token in ("-b", "--data-binary", "--data-raw"):
i += 1 i += 1
args["data_binary"] = tokens[i] args["data_binary"] = tokens[i]
args["method"] = "post"
elif token in ("-H", "--header"): elif token in ("-H", "--header"):
i += 1 i += 1
args["headers"].append(tokens[i]) args["headers"].append(tokens[i])
@ -106,6 +105,8 @@ def parse_curl_command(curl_command):
args["url"] = token args["url"] = token
i += 1 i += 1
args["method"] = method_on_curl or args["method"]
return ParsedArgs(**args) return ParsedArgs(**args)

View file

@ -1,12 +1,14 @@
import json import unicodedata
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from concurrent import futures from concurrent import futures
from pathlib import Path from pathlib import Path
from typing import Callable, List, Optional, Text from typing import Callable, List, Optional, Text
import chardet import chardet
import orjson
import yaml import yaml
from langflow.schema.schema import Record from langflow.schema import Record
# Types of files that can be read simply by file.read() # Types of files that can be read simply by file.read()
# and have 100% to be completely readable # and have 100% to be completely readable
@ -31,6 +33,17 @@ TEXT_FILE_TYPES = [
"tsx", "tsx",
] ]
IMG_FILE_TYPES = [
"jpg",
"jpeg",
"png",
"bmp",
]
def normalize_text(text):
return unicodedata.normalize("NFKD", text)
def is_hidden(path: Path) -> bool: def is_hidden(path: Path) -> bool:
return path.name.startswith(".") return path.name.startswith(".")
@ -94,6 +107,9 @@ def read_text_file(file_path: str) -> str:
result = chardet.detect(raw_data) result = chardet.detect(raw_data)
encoding = result["encoding"] encoding = result["encoding"]
if encoding in ["Windows-1252", "Windows-1254"]:
encoding = "utf-8"
with open(file_path, "r", encoding=encoding) as f: with open(file_path, "r", encoding=encoding) as f:
return f.read() return f.read()
@ -121,9 +137,15 @@ def parse_text_file_to_record(file_path: str, silent_errors: bool) -> Optional[R
text = read_docx_file(file_path) text = read_docx_file(file_path)
else: else:
text = read_text_file(file_path) text = read_text_file(file_path)
# if file is json, yaml, or xml, we can parse it # if file is json, yaml, or xml, we can parse it
if file_path.endswith(".json"): if file_path.endswith(".json"):
text = json.loads(text) text = orjson.loads(text)
if isinstance(text, dict):
text = {k: normalize_text(v) if isinstance(v, str) else v for k, v in text.items()}
elif isinstance(text, list):
text = [normalize_text(item) if isinstance(item, str) else item for item in text]
elif file_path.endswith(".yaml") or file_path.endswith(".yml"): elif file_path.endswith(".yaml") or file_path.endswith(".yml"):
text = yaml.safe_load(text) text = yaml.safe_load(text)
elif file_path.endswith(".xml"): elif file_path.endswith(".xml"):

View file

@ -1,7 +1,7 @@
from typing import List from typing import List
from langflow.graph.schema import ResultData, RunOutputs from langflow.graph.schema import ResultData, RunOutputs
from langflow.schema.schema import Record from langflow.schema import Record
def build_records_from_run_outputs(run_outputs: RunOutputs) -> List[Record]: def build_records_from_run_outputs(run_outputs: RunOutputs) -> List[Record]:

View file

@ -1,10 +1,10 @@
from typing import Optional, Union from typing import Optional, Union
from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES
from langflow.custom import Component from langflow.custom import Component
from langflow.field_typing import Text
from langflow.helpers.record import records_to_text
from langflow.memory import store_message from langflow.memory import store_message
from langflow.schema import Record from langflow.schema import Record
from langflow.schema.message import Message
class ChatComponent(Component): class ChatComponent(Component):
@ -15,7 +15,7 @@ class ChatComponent(Component):
return { return {
"input_value": { "input_value": {
"input_types": ["Text"], "input_types": ["Text"],
"display_name": "Message", "display_name": "Text",
"multiline": True, "multiline": True,
}, },
"sender": { "sender": {
@ -40,98 +40,45 @@ class ChatComponent(Component):
"info": "In case of Message being a Record, this template will be used to convert it to text.", "info": "In case of Message being a Record, this template will be used to convert it to text.",
"advanced": True, "advanced": True,
}, },
"files": {
"field_type": "file",
"display_name": "Files",
"file_types": TEXT_FILE_TYPES + IMG_FILE_TYPES,
"info": "Files to be sent with the message.",
"advanced": True,
},
} }
def store_message( def store_message(
self, self,
message: Union[str, Text, Record], message: Message,
session_id: Optional[str] = None, ) -> list[Message]:
sender: Optional[str] = None, messages = store_message(
sender_name: Optional[str] = None,
) -> list[Record]:
records = store_message(
message, message,
session_id=session_id,
sender=sender,
sender_name=sender_name,
flow_id=self.graph.flow_id, flow_id=self.graph.flow_id,
) )
self.status = records self.status = messages
return records return messages
def build_with_record( def build_with_record(
self, self,
sender: Optional[str] = "User", sender: Optional[str] = "User",
sender_name: Optional[str] = "User", sender_name: Optional[str] = "User",
input_value: Optional[Union[str, Record]] = None, input_value: Optional[Union[str, Record, Message]] = None,
files: Optional[list[str]] = None,
session_id: Optional[str] = None, session_id: Optional[str] = None,
return_record: Optional[bool] = False, ) -> Message:
record_template: str = "Text: {text}\nData: {data}", message: Message | None = None
) -> Union[Text, Record]:
input_value_record: Optional[Record] = None
if return_record:
if isinstance(input_value, Record):
# Update the data of the record
input_value.data["sender"] = sender
input_value.data["sender_name"] = sender_name
input_value.data["session_id"] = session_id
else:
input_value_record = Record(
text=input_value,
data={
"sender": sender,
"sender_name": sender_name,
"session_id": session_id,
},
)
elif isinstance(input_value, Record):
input_value = records_to_text(template=record_template, records=input_value)
if not input_value:
input_value = ""
if return_record and input_value_record:
result: Union[Text, Record] = input_value_record
else:
result = input_value
self.status = result
if session_id and isinstance(result, (Record, str)):
self.store_message(result, session_id, sender, sender_name)
return result
def build_no_record( if isinstance(input_value, Record):
self, # Update the data of the record
sender: Optional[str] = "User", message = Message.from_record(input_value)
sender_name: Optional[str] = "User",
input_value: Optional[str] = None,
session_id: Optional[str] = None,
return_record: Optional[bool] = False,
record_template: str = "Text: {text}\nData: {data}",
) -> Union[Text, Record]:
input_value_record: Optional[Record] = None
if return_record:
if isinstance(input_value, Record):
# Update the data of the record
input_value.data["sender"] = sender
input_value.data["sender_name"] = sender_name
input_value.data["session_id"] = session_id
else:
input_value_record = Record(
text=input_value,
data={
"sender": sender,
"sender_name": sender_name,
"session_id": session_id,
},
)
elif isinstance(input_value, Record):
input_value = records_to_text(template=record_template, records=input_value)
if not input_value:
input_value = ""
if return_record and input_value_record:
result: Union[Text, Record] = input_value_record
else: else:
result = input_value message = Message(
self.status = result text=input_value, sender=sender, sender_name=sender_name, files=files, session_id=session_id
if session_id and isinstance(result, (Record, str)): )
self.store_message(result, session_id, sender, sender_name) self.status = message
return result if session_id and isinstance(message, Message):
self.store_message(message)
return message

View file

@ -3,7 +3,7 @@ from typing import Optional
from langflow.custom import Component from langflow.custom import Component
from langflow.field_typing import Text from langflow.field_typing import Text
from langflow.helpers.record import records_to_text from langflow.helpers.record import records_to_text
from langflow.schema.schema import Record from langflow.schema import Record
class TextComponent(Component): class TextComponent(Component):

View file

@ -1,7 +1,7 @@
from typing import Optional from typing import Optional
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
class BaseMemoryComponent(CustomComponent): class BaseMemoryComponent(CustomComponent):

View file

@ -1,3 +1,4 @@
import warnings
from typing import Optional, Union from typing import Optional, Union
from langchain_core.language_models.chat_models import BaseChatModel from langchain_core.language_models.chat_models import BaseChatModel
@ -5,6 +6,7 @@ from langchain_core.language_models.llms import LLM
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing.prompt import Prompt
class LCModelComponent(CustomComponent): class LCModelComponent(CustomComponent):
@ -53,19 +55,28 @@ class LCModelComponent(CustomComponent):
key in response_metadata["token_usage"] for key in inner_openai_keys key in response_metadata["token_usage"] for key in inner_openai_keys
): ):
token_usage = response_metadata["token_usage"] token_usage = response_metadata["token_usage"]
completion_tokens = token_usage["completion_tokens"] status_message = {
prompt_tokens = token_usage["prompt_tokens"] "tokens": {
total_tokens = token_usage["total_tokens"] "input": token_usage["prompt_tokens"],
finish_reason = response_metadata["finish_reason"] "output": token_usage["completion_tokens"],
status_message = f"Tokens:\nInput: {prompt_tokens}\nOutput: {completion_tokens}\nTotal Tokens: {total_tokens}\nStop Reason: {finish_reason}\nResponse: {content}" "total": token_usage["total_tokens"],
"stop_reason": response_metadata["finish_reason"],
"response": content,
}
}
elif all(key in response_metadata for key in anthropic_keys) and all( elif all(key in response_metadata for key in anthropic_keys) and all(
key in response_metadata["usage"] for key in inner_anthropic_keys key in response_metadata["usage"] for key in inner_anthropic_keys
): ):
usage = response_metadata["usage"] usage = response_metadata["usage"]
input_tokens = usage["input_tokens"] status_message = {
output_tokens = usage["output_tokens"] "tokens": {
stop_reason = response_metadata["stop_reason"] "input": usage["input_tokens"],
status_message = f"Tokens:\nInput: {input_tokens}\nOutput: {output_tokens}\nStop Reason: {stop_reason}\nResponse: {content}" "output": usage["output_tokens"],
"stop_reason": response_metadata["stop_reason"],
"response": content,
}
}
else: else:
status_message = f"Response: {content}" status_message = f"Response: {content}"
else: else:
@ -73,7 +84,7 @@ class LCModelComponent(CustomComponent):
return status_message return status_message
def get_chat_result( def get_chat_result(
self, runnable: BaseChatModel, stream: bool, input_value: str, system_message: Optional[str] = None self, runnable: BaseChatModel, stream: bool, input_value: str | Prompt, system_message: Optional[str] = None
): ):
messages: list[Union[HumanMessage, SystemMessage]] = [] messages: list[Union[HumanMessage, SystemMessage]] = []
if not input_value and not system_message: if not input_value and not system_message:
@ -81,11 +92,21 @@ class LCModelComponent(CustomComponent):
if system_message: if system_message:
messages.append(SystemMessage(content=system_message)) messages.append(SystemMessage(content=system_message))
if input_value: if input_value:
messages.append(HumanMessage(content=input_value)) if isinstance(input_value, Prompt):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
if "prompt" in input_value:
prompt = input_value.load_lc_prompt()
runnable = prompt | runnable
else:
messages.append(input_value.to_lc_message())
else:
messages.append(HumanMessage(content=input_value))
inputs = messages or {}
if stream: if stream:
return runnable.stream(messages) return runnable.stream(inputs)
else: else:
message = runnable.invoke(messages) message = runnable.invoke(inputs)
result = message.content result = message.content
if isinstance(message, AIMessage): if isinstance(message, AIMessage):
status_message = self.build_status_message(message) status_message = self.build_status_message(message)

View file

@ -1,9 +1,9 @@
from copy import deepcopy from copy import deepcopy
from langchain_core.documents import Document from langchain_core.documents import Document
from langflow.schema import Record from langflow.schema import Record
from langflow.schema.message import Message
def record_to_string(record: Record) -> str: def record_to_string(record: Record) -> str:
@ -35,10 +35,14 @@ def dict_values_to_string(d: dict) -> dict:
# it could be a list of records or documents or strings # it could be a list of records or documents or strings
if isinstance(value, list): if isinstance(value, list):
for i, item in enumerate(value): for i, item in enumerate(value):
if isinstance(item, Record): if isinstance(item, Message):
d_copy[key][i] = item.text
elif isinstance(item, Record):
d_copy[key][i] = record_to_string(item) d_copy[key][i] = record_to_string(item)
elif isinstance(item, Document): elif isinstance(item, Document):
d_copy[key][i] = document_to_string(item) d_copy[key][i] = document_to_string(item)
elif isinstance(value, Message):
d_copy[key] = value.text
elif isinstance(value, Record): elif isinstance(value, Record):
d_copy[key] = record_to_string(value) d_copy[key] = record_to_string(value)
elif isinstance(value, Document): elif isinstance(value, Document):

View file

@ -5,7 +5,7 @@ from langchain_core.prompts import ChatPromptTemplate
from langflow.base.agents.agent import LCAgentComponent from langflow.base.agents.agent import LCAgentComponent
from langflow.field_typing import BaseLanguageModel, Text, Tool from langflow.field_typing import BaseLanguageModel, Text, Tool
from langflow.schema.schema import Record from langflow.schema import Record
class ToolCallingAgentComponent(LCAgentComponent): class ToolCallingAgentComponent(LCAgentComponent):

View file

@ -3,10 +3,9 @@ from typing import List, Optional
from langchain.agents import create_xml_agent from langchain.agents import create_xml_agent
from langchain_core.prompts import ChatPromptTemplate from langchain_core.prompts import ChatPromptTemplate
from langflow.base.agents.agent import LCAgentComponent from langflow.base.agents.agent import LCAgentComponent
from langflow.field_typing import BaseLanguageModel, Text, Tool from langflow.field_typing import BaseLanguageModel, Text, Tool
from langflow.schema.schema import Record from langflow.schema import Record
class XMLAgentComponent(LCAgentComponent): class XMLAgentComponent(LCAgentComponent):

View file

@ -5,7 +5,7 @@ from langchain_core.documents import Document
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import BaseLanguageModel, BaseMemory, BaseRetriever, Text from langflow.field_typing import BaseLanguageModel, BaseMemory, BaseRetriever, Text
from langflow.schema.schema import Record from langflow.schema import Record
class RetrievalQAComponent(CustomComponent): class RetrievalQAComponent(CustomComponent):

View file

@ -3,8 +3,8 @@ import uuid
from typing import Any, Optional from typing import Any, Optional
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema import Record
from langflow.schema.dotdict import dotdict from langflow.schema.dotdict import dotdict
from langflow.schema.schema import Record
class WebhookComponent(CustomComponent): class WebhookComponent(CustomComponent):

View file

@ -6,8 +6,8 @@ from langchain_core.prompts.chat import HumanMessagePromptTemplate, SystemMessag
from langflow.base.agents.agent import LCAgentComponent from langflow.base.agents.agent import LCAgentComponent
from langflow.base.agents.utils import AGENTS, AgentSpec, get_agents_list from langflow.base.agents.utils import AGENTS, AgentSpec, get_agents_list
from langflow.field_typing import BaseLanguageModel, Text, Tool from langflow.field_typing import BaseLanguageModel, Text, Tool
from langflow.schema import Record
from langflow.schema.dotdict import dotdict from langflow.schema.dotdict import dotdict
from langflow.schema.schema import Record
class AgentComponent(LCAgentComponent): class AgentComponent(LCAgentComponent):

View file

@ -7,8 +7,8 @@ from langflow.custom import CustomComponent
from langflow.field_typing import Tool from langflow.field_typing import Tool
from langflow.graph.graph.base import Graph from langflow.graph.graph.base import Graph
from langflow.helpers.flow import get_flow_inputs from langflow.helpers.flow import get_flow_inputs
from langflow.schema import Record
from langflow.schema.dotdict import dotdict from langflow.schema.dotdict import dotdict
from langflow.schema.schema import Record
class FlowToolComponent(CustomComponent): class FlowToolComponent(CustomComponent):

View file

@ -2,7 +2,7 @@ from typing import List, Optional
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.memory import get_messages, store_message from langflow.memory import get_messages, store_message
from langflow.schema import Record from langflow.schema.message import Message
class StoreMessageComponent(CustomComponent): class StoreMessageComponent(CustomComponent):
@ -31,12 +31,11 @@ class StoreMessageComponent(CustomComponent):
sender_name: Optional[str] = None, sender_name: Optional[str] = None,
session_id: Optional[str] = None, session_id: Optional[str] = None,
message: str = "", message: str = "",
) -> List[Record]: ) -> List[Message]:
store_message( store_message(
sender=sender, message=Message(
sender_name=sender_name, text=message, sender=sender, sender_name=sender_name, flow_id=self.graph.flow_id, session_id=session_id
session_id=session_id, )
message=message,
) )
self.status = get_messages(session_id=session_id) self.status = get_messages(session_id=session_id)

View file

@ -2,9 +2,9 @@ from typing import Optional
from langflow.base.memory.memory import BaseMemoryComponent from langflow.base.memory.memory import BaseMemoryComponent
from langflow.field_typing import Text from langflow.field_typing import Text
from langflow.helpers.record import records_to_text from langflow.helpers.record import messages_to_text
from langflow.memory import get_messages from langflow.memory import get_messages
from langflow.schema.schema import Record from langflow.schema.message import Message
class MemoryComponent(BaseMemoryComponent): class MemoryComponent(BaseMemoryComponent):
@ -43,7 +43,7 @@ class MemoryComponent(BaseMemoryComponent):
}, },
} }
def get_messages(self, **kwargs) -> list[Record]: def get_messages(self, **kwargs) -> list[Message]:
# Validate kwargs by checking if it contains the correct keys # Validate kwargs by checking if it contains the correct keys
if "sender" not in kwargs: if "sender" not in kwargs:
kwargs["sender"] = None kwargs["sender"] = None
@ -77,6 +77,6 @@ class MemoryComponent(BaseMemoryComponent):
limit=n_messages, limit=n_messages,
order=order, order=order,
) )
messages_str = records_to_text(template=record_template or "", records=messages) messages_str = messages_to_text(template=record_template or "", messages=messages)
self.status = messages_str self.status = messages_str
return messages_str return messages_str

View file

@ -1,7 +1,6 @@
from langchain_core.prompts import PromptTemplate
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import Input, Prompt, Text from langflow.field_typing import Input
from langflow.field_typing.prompt import Prompt
class PromptComponent(CustomComponent): class PromptComponent(CustomComponent):
@ -15,19 +14,11 @@ class PromptComponent(CustomComponent):
"code": Input(advanced=True), "code": Input(advanced=True),
} }
def build( async def build(
self, self,
template: Prompt, template: Prompt,
**kwargs, **kwargs,
) -> Text: ) -> Prompt:
from langflow.base.prompts.utils import dict_values_to_string prompt = await Prompt.from_template_and_variables(template, kwargs)
self.status = prompt.format_text()
prompt_template = PromptTemplate.from_template(Text(template)) return prompt
kwargs = dict_values_to_string(kwargs)
kwargs = {k: "\n".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}
try:
formated_prompt = prompt_template.format(**kwargs)
except Exception as exc:
raise ValueError(f"Error formatting prompt: {exc}") from exc
self.status = f'Prompt:\n"{formated_prompt}"'
return formated_prompt

View file

@ -3,7 +3,7 @@ from typing import Optional
from langchain_community.utilities.searchapi import SearchApiAPIWrapper from langchain_community.utilities.searchapi import SearchApiAPIWrapper
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
from langflow.services.database.models.base import orjson_dumps from langflow.services.database.models.base import orjson_dumps

View file

@ -4,7 +4,7 @@ from langchain_astradb.chat_message_histories import AstraDBChatMessageHistory
from langflow.base.memory.memory import BaseMemoryComponent from langflow.base.memory.memory import BaseMemoryComponent
from langflow.field_typing import Text from langflow.field_typing import Text
from langflow.schema.schema import Record from langflow.schema import Record
class AstraDBMessageReaderComponent(BaseMemoryComponent): class AstraDBMessageReaderComponent(BaseMemoryComponent):

View file

@ -1,11 +1,11 @@
from typing import Optional from typing import Optional
from langchain_astradb import AstraDBChatMessageHistory
from langchain_core.messages import BaseMessage
from langflow.base.memory.memory import BaseMemoryComponent from langflow.base.memory.memory import BaseMemoryComponent
from langflow.field_typing import Text from langflow.field_typing import Text
from langflow.schema.schema import Record from langflow.schema import Record
from langchain_core.messages import BaseMessage
from langchain_astradb import AstraDBChatMessageHistory
class AstraDBMessageWriterComponent(BaseMemoryComponent): class AstraDBMessageWriterComponent(BaseMemoryComponent):

View file

@ -4,7 +4,7 @@ from langchain_community.chat_message_histories.zep import SearchScope, SearchTy
from langflow.base.memory.memory import BaseMemoryComponent from langflow.base.memory.memory import BaseMemoryComponent
from langflow.field_typing import Text from langflow.field_typing import Text
from langflow.schema.schema import Record from langflow.schema import Record
class ZepMessageReaderComponent(BaseMemoryComponent): class ZepMessageReaderComponent(BaseMemoryComponent):

View file

@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Optional
from langflow.base.memory.memory import BaseMemoryComponent from langflow.base.memory.memory import BaseMemoryComponent
from langflow.field_typing import Text from langflow.field_typing import Text
from langflow.schema.schema import Record from langflow.schema import Record
if TYPE_CHECKING: if TYPE_CHECKING:
from zep_python.langchain import ZepChatMessageHistory from zep_python.langchain import ZepChatMessageHistory

View file

@ -58,7 +58,7 @@ class AmazonBedrockComponent(LCModelComponent):
"advanced": True, "advanced": True,
}, },
"cache": {"display_name": "Cache"}, "cache": {"display_name": "Cache"},
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"system_message": { "system_message": {
"display_name": "System Message", "display_name": "System Message",
"info": "System message to pass to the model.", "info": "System message to pass to the model.",

View file

@ -63,7 +63,7 @@ class AnthropicLLM(LCModelComponent):
"info": "Endpoint of the Anthropic API. Defaults to 'https://api.anthropic.com' if not specified.", "info": "Endpoint of the Anthropic API. Defaults to 'https://api.anthropic.com' if not specified.",
}, },
"code": {"show": False}, "code": {"show": False},
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"stream": { "stream": {
"display_name": "Stream", "display_name": "Stream",
"advanced": True, "advanced": True,

View file

@ -78,7 +78,7 @@ class AzureChatOpenAIComponent(LCModelComponent):
"info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
}, },
"code": {"show": False}, "code": {"show": False},
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"stream": { "stream": {
"display_name": "Stream", "display_name": "Stream",
"info": STREAM_INFO_TEXT, "info": STREAM_INFO_TEXT,

View file

@ -81,7 +81,7 @@ class QianfanChatEndpointComponent(LCModelComponent):
"info": "Endpoint of the Qianfan LLM, required if custom model used.", "info": "Endpoint of the Qianfan LLM, required if custom model used.",
}, },
"code": {"show": False}, "code": {"show": False},
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"stream": { "stream": {
"display_name": "Stream", "display_name": "Stream",
"info": STREAM_INFO_TEXT, "info": STREAM_INFO_TEXT,

View file

@ -111,7 +111,7 @@ class ChatLiteLLMModelComponent(LCModelComponent):
"required": False, "required": False,
"default": False, "default": False,
}, },
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"stream": { "stream": {
"display_name": "Stream", "display_name": "Stream",
"info": STREAM_INFO_TEXT, "info": STREAM_INFO_TEXT,

View file

@ -1,10 +1,11 @@
from typing import Optional from typing import Optional
from langchain_cohere import ChatCohere
from pydantic.v1 import SecretStr from pydantic.v1 import SecretStr
from langflow.field_typing import Text
from langflow.base.constants import STREAM_INFO_TEXT from langflow.base.constants import STREAM_INFO_TEXT
from langflow.base.models.model import LCModelComponent from langflow.base.models.model import LCModelComponent
from langchain_cohere import ChatCohere from langflow.field_typing import Text
class CohereComponent(LCModelComponent): class CohereComponent(LCModelComponent):
@ -42,7 +43,7 @@ class CohereComponent(LCModelComponent):
"type": "float", "type": "float",
"show": True, "show": True,
}, },
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"stream": { "stream": {
"display_name": "Stream", "display_name": "Stream",
"info": STREAM_INFO_TEXT, "info": STREAM_INFO_TEXT,
@ -69,3 +70,4 @@ class CohereComponent(LCModelComponent):
temperature=temperature, temperature=temperature,
) )
return self.get_chat_result(output, stream, input_value, system_message) return self.get_chat_result(output, stream, input_value, system_message)
return self.get_chat_result(output, stream, input_value, system_message)

View file

@ -2,9 +2,10 @@ from typing import Optional
from langchain_community.chat_models.huggingface import ChatHuggingFace from langchain_community.chat_models.huggingface import ChatHuggingFace
from langchain_community.llms.huggingface_endpoint import HuggingFaceEndpoint from langchain_community.llms.huggingface_endpoint import HuggingFaceEndpoint
from langflow.field_typing import Text
from langflow.base.constants import STREAM_INFO_TEXT from langflow.base.constants import STREAM_INFO_TEXT
from langflow.base.models.model import LCModelComponent from langflow.base.models.model import LCModelComponent
from langflow.field_typing import Text
class HuggingFaceEndpointsComponent(LCModelComponent): class HuggingFaceEndpointsComponent(LCModelComponent):
@ -36,7 +37,7 @@ class HuggingFaceEndpointsComponent(LCModelComponent):
"advanced": True, "advanced": True,
}, },
"code": {"show": False}, "code": {"show": False},
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"stream": { "stream": {
"display_name": "Stream", "display_name": "Stream",
"info": STREAM_INFO_TEXT, "info": STREAM_INFO_TEXT,
@ -72,3 +73,4 @@ class HuggingFaceEndpointsComponent(LCModelComponent):
raise ValueError("Could not connect to HuggingFace Endpoints API.") from e raise ValueError("Could not connect to HuggingFace Endpoints API.") from e
output = ChatHuggingFace(llm=llm) output = ChatHuggingFace(llm=llm)
return self.get_chat_result(output, stream, input_value, system_message) return self.get_chat_result(output, stream, input_value, system_message)
return self.get_chat_result(output, stream, input_value, system_message)

View file

@ -27,7 +27,7 @@ class MistralAIModelComponent(LCModelComponent):
def build_config(self): def build_config(self):
return { return {
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"max_tokens": { "max_tokens": {
"display_name": "Max Tokens", "display_name": "Max Tokens",
"advanced": True, "advanced": True,

View file

@ -194,7 +194,7 @@ class ChatOllamaComponent(LCModelComponent):
"info": "Template to use for generating text.", "info": "Template to use for generating text.",
"advanced": True, "advanced": True,
}, },
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"stream": { "stream": {
"display_name": "Stream", "display_name": "Stream",
"info": STREAM_INFO_TEXT, "info": STREAM_INFO_TEXT,

View file

@ -28,7 +28,7 @@ class OpenAIModelComponent(LCModelComponent):
def build_config(self): def build_config(self):
return { return {
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"max_tokens": { "max_tokens": {
"display_name": "Max Tokens", "display_name": "Max Tokens",
"advanced": True, "advanced": True,
@ -79,7 +79,7 @@ class OpenAIModelComponent(LCModelComponent):
input_value: Text, input_value: Text,
openai_api_key: str, openai_api_key: str,
temperature: float = 0.1, temperature: float = 0.1,
model_name: str = "gpt-4o", model_name: str = "gpt-3.5-turbo",
max_tokens: Optional[int] = 256, max_tokens: Optional[int] = 256,
model_kwargs: NestedDict = {}, model_kwargs: NestedDict = {},
openai_api_base: Optional[str] = None, openai_api_base: Optional[str] = None,

View file

@ -1,6 +1,5 @@
from typing import Optional from typing import Optional
from langflow.base.constants import STREAM_INFO_TEXT from langflow.base.constants import STREAM_INFO_TEXT
from langflow.base.models.model import LCModelComponent from langflow.base.models.model import LCModelComponent
from langflow.field_typing import Text from langflow.field_typing import Text
@ -74,7 +73,7 @@ class ChatVertexAIComponent(LCModelComponent):
"value": False, "value": False,
"advanced": True, "advanced": True,
}, },
"input_value": {"display_name": "Input"}, "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]},
"stream": { "stream": {
"display_name": "Stream", "display_name": "Stream",
"info": STREAM_INFO_TEXT, "info": STREAM_INFO_TEXT,

View file

@ -3,7 +3,7 @@ from typing import List
from langchain_text_splitters import CharacterTextSplitter from langchain_text_splitters import CharacterTextSplitter
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
from langflow.utils.util import unescape_string from langflow.utils.util import unescape_string

View file

@ -3,7 +3,7 @@ from typing import List, Optional
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter from langchain_text_splitters import Language, RecursiveCharacterTextSplitter
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
class LanguageRecursiveTextSplitterComponent(CustomComponent): class LanguageRecursiveTextSplitterComponent(CustomComponent):

View file

@ -3,7 +3,7 @@ from typing import Optional
from langchain_community.utilities.searchapi import SearchApiAPIWrapper from langchain_community.utilities.searchapi import SearchApiAPIWrapper
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
from langflow.services.database.models.base import orjson_dumps from langflow.services.database.models.base import orjson_dumps

View file

@ -1,10 +1,11 @@
from typing import List, Optional from typing import List, Optional
from langchain_core.embeddings import Embeddings
from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.base.model import LCVectorStoreComponent
from langflow.components.vectorstores.Redis import RedisComponent from langflow.components.vectorstores.Redis import RedisComponent
from langflow.field_typing import Text from langflow.field_typing import Text
from langflow.schema import Record from langflow.schema import Record
from langchain_core.embeddings import Embeddings
class RedisSearchComponent(RedisComponent, LCVectorStoreComponent): class RedisSearchComponent(RedisComponent, LCVectorStoreComponent):

View file

@ -1,10 +1,11 @@
from typing import List, Optional from typing import List, Optional
from langchain_core.embeddings import Embeddings
from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.base.model import LCVectorStoreComponent
from langflow.components.vectorstores.Weaviate import WeaviateVectorStoreComponent from langflow.components.vectorstores.Weaviate import WeaviateVectorStoreComponent
from langflow.field_typing import Text from langflow.field_typing import Text
from langflow.schema import Record from langflow.schema import Record
from langchain_core.embeddings import Embeddings
class WeaviateSearchVectorStore(WeaviateVectorStoreComponent, LCVectorStoreComponent): class WeaviateSearchVectorStore(WeaviateVectorStoreComponent, LCVectorStoreComponent):

View file

@ -1,10 +1,11 @@
from typing import List from typing import List
from langchain_core.embeddings import Embeddings
from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.base.model import LCVectorStoreComponent
from langflow.components.vectorstores.pgvector import PGVectorComponent from langflow.components.vectorstores.pgvector import PGVectorComponent
from langflow.field_typing import Text from langflow.field_typing import Text
from langflow.schema import Record from langflow.schema import Record
from langchain_core.embeddings import Embeddings
class PGVectorSearchComponent(PGVectorComponent, LCVectorStoreComponent): class PGVectorSearchComponent(PGVectorComponent, LCVectorStoreComponent):

View file

@ -1,11 +1,12 @@
from typing import List, Optional, Union from typing import List, Optional, Union
from langchain_astradb import AstraDBVectorStore from langchain_astradb import AstraDBVectorStore
from langchain_astradb.utils.astradb import SetupMode from langchain_astradb.utils.astradb import SetupMode
from langchain_core.retrievers import BaseRetriever
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import Embeddings, VectorStore from langflow.field_typing import Embeddings, VectorStore
from langflow.schema import Record from langflow.schema import Record
from langchain_core.retrievers import BaseRetriever
class AstraDBVectorStoreComponent(CustomComponent): class AstraDBVectorStoreComponent(CustomComponent):
@ -156,3 +157,4 @@ class AstraDBVectorStoreComponent(CustomComponent):
) )
return vector_store return vector_store
return vector_store

View file

@ -8,7 +8,7 @@ from langchain_core.retrievers import BaseRetriever
from langchain_core.vectorstores import VectorStore from langchain_core.vectorstores import VectorStore
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
class ChromaComponent(CustomComponent): class ChromaComponent(CustomComponent):

View file

@ -1,18 +1,16 @@
from typing import List, Optional, Union
from langchain_community.vectorstores import CouchbaseVectorStore
from langflow.custom import CustomComponent
from langflow.field_typing import Embeddings, VectorStore
from langflow.schema import Record
from datetime import timedelta from datetime import timedelta
from typing import List, Optional, Union
from couchbase.auth import PasswordAuthenticator # type: ignore from couchbase.auth import PasswordAuthenticator # type: ignore
from couchbase.cluster import Cluster # type: ignore from couchbase.cluster import Cluster # type: ignore
from couchbase.options import ClusterOptions # type: ignore from couchbase.options import ClusterOptions # type: ignore
from langchain_community.vectorstores import CouchbaseVectorStore
from langchain_core.retrievers import BaseRetriever from langchain_core.retrievers import BaseRetriever
from langflow.custom import CustomComponent
from langflow.field_typing import Embeddings, VectorStore
from langflow.schema import Record
class CouchbaseComponent(CustomComponent): class CouchbaseComponent(CustomComponent):
display_name = "Couchbase" display_name = "Couchbase"

View file

@ -6,7 +6,7 @@ from langchain_core.vectorstores import VectorStore
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import Embeddings from langflow.field_typing import Embeddings
from langflow.schema.schema import Record from langflow.schema import Record
class FAISSComponent(CustomComponent): class FAISSComponent(CustomComponent):

View file

@ -4,7 +4,7 @@ from langchain_community.vectorstores.mongodb_atlas import MongoDBAtlasVectorSea
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import Embeddings from langflow.field_typing import Embeddings
from langflow.schema.schema import Record from langflow.schema import Record
class MongoDBAtlasComponent(CustomComponent): class MongoDBAtlasComponent(CustomComponent):

View file

@ -8,7 +8,7 @@ from langchain_pinecone.vectorstores import PineconeVectorStore
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import Embeddings from langflow.field_typing import Embeddings
from langflow.schema.schema import Record from langflow.schema import Record
class PineconeComponent(CustomComponent): class PineconeComponent(CustomComponent):

View file

@ -6,7 +6,7 @@ from langchain_core.vectorstores import VectorStore
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import Embeddings from langflow.field_typing import Embeddings
from langflow.schema.schema import Record from langflow.schema import Record
class QdrantComponent(CustomComponent): class QdrantComponent(CustomComponent):

View file

@ -6,7 +6,7 @@ from langchain_core.retrievers import BaseRetriever
from langchain_core.vectorstores import VectorStore from langchain_core.vectorstores import VectorStore
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
class RedisComponent(CustomComponent): class RedisComponent(CustomComponent):

View file

@ -7,7 +7,7 @@ from supabase.client import Client, create_client
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import Embeddings from langflow.field_typing import Embeddings
from langflow.schema.schema import Record from langflow.schema import Record
class SupabaseComponent(CustomComponent): class SupabaseComponent(CustomComponent):

View file

@ -6,7 +6,7 @@ from langchain_core.retrievers import BaseRetriever
from langchain_core.vectorstores import VectorStore from langchain_core.vectorstores import VectorStore
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
class UpstashVectorStoreComponent(CustomComponent): class UpstashVectorStoreComponent(CustomComponent):

View file

@ -9,7 +9,7 @@ from langchain_core.vectorstores import VectorStore
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.field_typing import BaseRetriever from langflow.field_typing import BaseRetriever
from langflow.schema.schema import Record from langflow.schema import Record
class VectaraComponent(CustomComponent): class VectaraComponent(CustomComponent):

View file

@ -8,7 +8,7 @@ from langchain_core.retrievers import BaseRetriever
from langchain_core.vectorstores import VectorStore from langchain_core.vectorstores import VectorStore
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
class WeaviateVectorStoreComponent(CustomComponent): class WeaviateVectorStoreComponent(CustomComponent):

View file

@ -6,7 +6,7 @@ from langchain_core.retrievers import BaseRetriever
from langchain_core.vectorstores import VectorStore from langchain_core.vectorstores import VectorStore
from langflow.custom import CustomComponent from langflow.custom import CustomComponent
from langflow.schema.schema import Record from langflow.schema import Record
class PGVectorComponent(CustomComponent): class PGVectorComponent(CustomComponent):

View file

@ -378,13 +378,14 @@ class CustomComponent(BaseComponent):
The variable for the current user with the specified name. The variable for the current user with the specified name.
""" """
def get_variable(name: str): def get_variable(name: str, field: str):
if hasattr(self, "_user_id") and not self._user_id: if hasattr(self, "_user_id") and not self._user_id:
raise ValueError(f"User id is not set for {self.__class__.__name__}") raise ValueError(f"User id is not set for {self.__class__.__name__}")
variable_service = get_variable_service() # Get service instance variable_service = get_variable_service() # Get service instance
# Retrieve and decrypt the variable by name for the current user # Retrieve and decrypt the variable by name for the current user
with session_scope() as session: with session_scope() as session:
return variable_service.get_variable(user_id=self._user_id or "", name=name, session=session) user_id = self._user_id or ""
return variable_service.get_variable(user_id=user_id, name=name, field=field, session=session)
return get_variable return get_variable

View file

@ -19,13 +19,13 @@ from .constants import (
Embeddings, Embeddings,
NestedDict, NestedDict,
Object, Object,
Prompt,
PromptTemplate, PromptTemplate,
Text, Text,
TextSplitter, TextSplitter,
Tool, Tool,
VectorStore, VectorStore,
) )
from .prompt import Prompt
from .range_spec import RangeSpec from .range_spec import RangeSpec

View file

@ -15,6 +15,8 @@ from langchain_core.tools import Tool
from langchain_core.vectorstores import VectorStore from langchain_core.vectorstores import VectorStore
from langchain_text_splitters import TextSplitter from langchain_text_splitters import TextSplitter
from langflow.field_typing.prompt import Prompt
# Type alias for more complex dicts # Type alias for more complex dicts
NestedDict = Dict[str, Union[str, Dict]] NestedDict = Dict[str, Union[str, Dict]]
@ -27,10 +29,6 @@ class Data:
pass pass
class Prompt:
pass
class Code: class Code:
pass pass

View file

@ -0,0 +1,41 @@
from langchain_core.load import load
from langchain_core.messages import HumanMessage
from langchain_core.prompts import BaseChatPromptTemplate, ChatPromptTemplate, PromptTemplate
from langflow.base.prompts.utils import dict_values_to_string
from langflow.schema.message import Message
from langflow.schema.record import Record
class Prompt(Record):
def load_lc_prompt(self):
if "prompt" not in self:
raise ValueError("Prompt is required.")
return load(self.prompt)
@classmethod
def from_lc_prompt(
cls,
prompt: BaseChatPromptTemplate,
):
prompt_json = prompt.to_json()
return cls(prompt=prompt_json)
def format_text(self):
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)
return formatted_prompt
@classmethod
async def from_template_and_variables(cls, template: str, variables: dict):
instance = cls(template=template, variables=variables)
contents = [{"type": "text", "text": instance.format_text()}]
# Get all Message instances from the kwargs
for value in variables.values():
if isinstance(value, Message):
content_dicts = await value.get_file_content_dicts()
contents.extend(content_dicts)
prompt_template = ChatPromptTemplate.from_messages([HumanMessage(content=contents)])
instance.prompt = prompt_template.to_json()
return instance

View file

@ -4,7 +4,6 @@ from collections import defaultdict, deque
from functools import partial from functools import partial
from itertools import chain from itertools import chain
from typing import TYPE_CHECKING, Callable, Coroutine, Dict, Generator, List, Optional, Tuple, Type, Union from typing import TYPE_CHECKING, Callable, Coroutine, Dict, Generator, List, Optional, Tuple, Type, Union
from loguru import logger from loguru import logger
from langflow.graph.edge.base import ContractEdge from langflow.graph.edge.base import ContractEdge
@ -20,6 +19,7 @@ from langflow.schema.schema import INPUT_FIELD_NAME, InputType
from langflow.services.cache.utils import CacheMiss from langflow.services.cache.utils import CacheMiss
from langflow.services.chat.service import ChatService from langflow.services.chat.service import ChatService
from langflow.services.deps import get_chat_service from langflow.services.deps import get_chat_service
from langflow.services.monitor.utils import log_transaction
if TYPE_CHECKING: if TYPE_CHECKING:
from langflow.graph.schema import ResultData from langflow.graph.schema import ResultData
@ -725,6 +725,7 @@ class Graph:
chat_service: ChatService, chat_service: ChatService,
vertex_id: str, vertex_id: str,
inputs_dict: Optional[Dict[str, str]] = None, inputs_dict: Optional[Dict[str, str]] = None,
files: Optional[list[str]] = None,
user_id: Optional[str] = None, user_id: Optional[str] = None,
fallback_to_env_vars: bool = False, fallback_to_env_vars: bool = False,
): ):
@ -752,7 +753,9 @@ class Graph:
# Check the cache for the vertex # Check the cache for the vertex
cached_result = await chat_service.get_cache(key=vertex.id) cached_result = await chat_service.get_cache(key=vertex.id)
if isinstance(cached_result, CacheMiss): if isinstance(cached_result, CacheMiss):
await vertex.build(user_id=user_id, inputs=inputs_dict, fallback_to_env_vars=fallback_to_env_vars) await vertex.build(
user_id=user_id, inputs=inputs_dict, fallback_to_env_vars=fallback_to_env_vars, files=files
)
await chat_service.set_cache(key=vertex.id, data=vertex) await chat_service.set_cache(key=vertex.id, data=vertex)
else: else:
cached_vertex = cached_result["result"] cached_vertex = cached_result["result"]
@ -766,7 +769,10 @@ class Graph:
vertex.result.used_frozen_result = True vertex.result.used_frozen_result = True
else: else:
await vertex.build(user_id=user_id, inputs=inputs_dict, fallback_to_env_vars=fallback_to_env_vars) await vertex.build(
user_id=user_id, inputs=inputs_dict, fallback_to_env_vars=fallback_to_env_vars, files=files
)
await chat_service.set_cache(key=vertex.id, data=vertex)
if vertex.result is not None: if vertex.result is not None:
params = f"{vertex._built_object_repr()}{params}" params = f"{vertex._built_object_repr()}{params}"
@ -779,9 +785,13 @@ class Graph:
next_runnable_vertices, top_level_vertices = await self.get_next_and_top_level_vertices( next_runnable_vertices, top_level_vertices = await self.get_next_and_top_level_vertices(
lock, set_cache_coro, vertex lock, set_cache_coro, vertex
) )
flow_id = self.flow_id
log_transaction(flow_id, vertex, status="success")
return next_runnable_vertices, top_level_vertices, result_dict, params, valid, artifacts, vertex return next_runnable_vertices, top_level_vertices, result_dict, params, valid, artifacts, vertex
except Exception as exc: except Exception as exc:
logger.exception(f"Error building vertex: {exc}") logger.exception(f"Error building vertex: {exc}")
flow_id = self.flow_id
log_transaction(flow_id, vertex, status="failure", error=str(exc))
raise exc raise exc
async def get_next_and_top_level_vertices( async def get_next_and_top_level_vertices(

View file

@ -1,15 +1,17 @@
from enum import Enum from enum import Enum
from typing import Any, List, Optional from typing import Any, List, Optional
from pydantic import BaseModel, Field, field_serializer from pydantic import BaseModel, Field, field_serializer, model_validator
from langflow.graph.utils import serialize_field from langflow.graph.utils import serialize_field
from langflow.schema.schema import Log, StreamURL
from langflow.utils.schemas import ChatOutputResponse, ContainsEnumMeta from langflow.utils.schemas import ChatOutputResponse, ContainsEnumMeta
class ResultData(BaseModel): class ResultData(BaseModel):
results: Optional[Any] = Field(default_factory=dict) results: Optional[Any] = Field(default_factory=dict)
artifacts: Optional[Any] = Field(default_factory=dict) artifacts: Optional[Any] = Field(default_factory=dict)
logs: Optional[List[dict]] = Field(default_factory=list)
messages: Optional[list[ChatOutputResponse]] = Field(default_factory=list) messages: Optional[list[ChatOutputResponse]] = Field(default_factory=list)
timedelta: Optional[float] = None timedelta: Optional[float] = None
duration: Optional[str] = None duration: Optional[str] = None
@ -23,6 +25,24 @@ class ResultData(BaseModel):
return {key: serialize_field(val) for key, val in value.items()} return {key: serialize_field(val) for key, val in value.items()}
return serialize_field(value) return serialize_field(value)
@model_validator(mode="before")
@classmethod
def validate_model(cls, values):
if not values.get("logs") and values.get("artifacts"):
# Build the log from the artifacts
message = values["artifacts"]
# ! Temporary fix
if not isinstance(message, dict):
message = {"message": message}
if "stream_url" in message and "type" in message:
stream_url = StreamURL(location=message["stream_url"])
values["logs"] = [Log(message=stream_url, type=message["type"])]
elif "type" in message:
values["logs"] = [Log(message=message, type=message["type"])]
return values
class InterfaceComponentTypes(str, Enum, metaclass=ContainsEnumMeta): class InterfaceComponentTypes(str, Enum, metaclass=ContainsEnumMeta):
# ChatInput and ChatOutput are the only ones that are # ChatInput and ChatOutput are the only ones that are

View file

@ -1,9 +1,12 @@
from typing import Any, Union from enum import Enum
from typing import Any, Generator, Union
from langchain_core.documents import Document from langchain_core.documents import Document
from pydantic import BaseModel from pydantic import BaseModel
from langflow.interface.utils import extract_input_variables_from_prompt from langflow.interface.utils import extract_input_variables_from_prompt
from langflow.schema import Record
from langflow.schema.message import Message
class UnbuiltObject: class UnbuiltObject:
@ -14,6 +17,16 @@ class UnbuiltResult:
pass pass
class ArtifactType(str, Enum):
TEXT = "text"
RECORD = "record"
OBJECT = "object"
ARRAY = "array"
STREAM = "stream"
UNKNOWN = "unknown"
MESSAGE = "message"
def validate_prompt(prompt: str): def validate_prompt(prompt: str):
"""Validate prompt.""" """Validate prompt."""
if extract_input_variables_from_prompt(prompt): if extract_input_variables_from_prompt(prompt):
@ -50,3 +63,38 @@ def serialize_field(value):
elif isinstance(value, str): elif isinstance(value, str):
return {"result": value} return {"result": value}
return value return value
def get_artifact_type(custom_component, build_result) -> str:
result = ArtifactType.UNKNOWN
value = custom_component.repr_value
match value:
case Record():
result = ArtifactType.RECORD
case str():
result = ArtifactType.TEXT
case dict():
result = ArtifactType.OBJECT
case list():
result = ArtifactType.ARRAY
case Message():
result = ArtifactType.MESSAGE
if result == ArtifactType.UNKNOWN:
if isinstance(build_result, Generator):
result = ArtifactType.STREAM
elif isinstance(value, Message) and isinstance(value.text, Generator):
result = ArtifactType.STREAM
return result.value
def post_process_raw(raw, artifact_type: str):
if artifact_type == ArtifactType.STREAM.value:
raw = ""
return raw

View file

@ -4,17 +4,17 @@ import inspect
import os import os
import types import types
from enum import Enum from enum import Enum
from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Dict, Iterator, List, Optional from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Dict, Iterator, List, Mapping, Optional
from loguru import logger from loguru import logger
from langflow.graph.schema import INPUT_COMPONENTS, OUTPUT_COMPONENTS, InterfaceComponentTypes, ResultData from langflow.graph.schema import INPUT_COMPONENTS, OUTPUT_COMPONENTS, InterfaceComponentTypes, ResultData
from langflow.graph.utils import UnbuiltObject, UnbuiltResult from langflow.graph.utils import ArtifactType, UnbuiltObject, UnbuiltResult
from langflow.graph.vertex.utils import log_transaction
from langflow.interface.initialize import loading from langflow.interface.initialize import loading
from langflow.interface.listing import lazy_load_dict from langflow.interface.listing import lazy_load_dict
from langflow.schema.schema import INPUT_FIELD_NAME from langflow.schema.schema import INPUT_FIELD_NAME
from langflow.services.deps import get_storage_service from langflow.services.deps import get_storage_service
from langflow.services.monitor.utils import log_transaction
from langflow.utils.constants import DIRECT_TYPES from langflow.utils.constants import DIRECT_TYPES
from langflow.utils.schemas import ChatOutputResponse from langflow.utils.schemas import ChatOutputResponse
from langflow.utils.util import sync_to_async, unescape_string from langflow.utils.util import sync_to_async, unescape_string
@ -63,6 +63,8 @@ class Vertex:
self._built_result = None self._built_result = None
self._built = False self._built = False
self.artifacts: Dict[str, Any] = {} self.artifacts: Dict[str, Any] = {}
self.artifacts_raw: Any = None
self.artifacts_type: Optional[str] = None
self.steps: List[Callable] = [self._build] self.steps: List[Callable] = [self._build]
self.steps_ran: List[Callable] = [] self.steps_ran: List[Callable] = []
self.task_id: Optional[str] = None self.task_id: Optional[str] = None
@ -394,7 +396,7 @@ class Vertex:
self.load_from_db_fields = load_from_db_fields self.load_from_db_fields = load_from_db_fields
self._raw_params = params.copy() self._raw_params = params.copy()
def update_raw_params(self, new_params: Dict[str, str], overwrite: bool = False): def update_raw_params(self, new_params: Mapping[str, str | list[str]], overwrite: bool = False):
""" """
Update the raw parameters of the vertex with the given new parameters. Update the raw parameters of the vertex with the given new parameters.
@ -445,11 +447,14 @@ class Vertex:
try: try:
messages = [ messages = [
ChatOutputResponse( ChatOutputResponse(
message=artifacts["message"], message=artifacts["text"],
sender=artifacts.get("sender"), sender=artifacts.get("sender"),
sender_name=artifacts.get("sender_name"), sender_name=artifacts.get("sender_name"),
session_id=artifacts.get("session_id"), session_id=artifacts.get("session_id"),
stream_url=artifacts.get("stream_url"),
files=[{"path": file} if isinstance(file, str) else file for file in artifacts.get("files", [])],
component_id=self.id, component_id=self.id,
type=self.artifacts_type,
).model_dump(exclude_none=True) ).model_dump(exclude_none=True)
] ]
except KeyError: except KeyError:
@ -462,12 +467,11 @@ class Vertex:
# We need to set the artifacts to pass information # We need to set the artifacts to pass information
# to the frontend # to the frontend
self.set_artifacts() self.set_artifacts()
artifacts = self.artifacts artifacts = self.artifacts_raw
if isinstance(artifacts, dict): if isinstance(artifacts, dict):
messages = self.extract_messages_from_artifacts(artifacts) messages = self.extract_messages_from_artifacts(artifacts)
else: else:
messages = [] messages = []
result_dict = ResultData( result_dict = ResultData(
results=result_dict, results=result_dict,
artifacts=artifacts, artifacts=artifacts,
@ -548,12 +552,13 @@ class Vertex:
Returns: Returns:
The built result if use_result is True, else the built object. The built result if use_result is True, else the built object.
""" """
flow_id = self.graph.flow_id
if not self._built: if not self._built:
log_transaction(source=self, target=requester, flow_id=self.graph.flow_id, status="error") log_transaction(flow_id, vertex=self, target=requester, status="error")
raise ValueError(f"Component {self.display_name} has not been built yet") raise ValueError(f"Component {self.display_name} has not been built yet")
result = self._built_result if self.use_result else self._built_object result = self._built_result if self.use_result else self._built_object
log_transaction(source=self, target=requester, flow_id=self.graph.flow_id, status="success") log_transaction(flow_id, vertex=self, target=requester, status="success")
return result return result
async def _build_vertex_and_update_params(self, key, vertex: "Vertex"): async def _build_vertex_and_update_params(self, key, vertex: "Vertex"):
@ -647,6 +652,8 @@ class Vertex:
self._built_object, self.artifacts = result self._built_object, self.artifacts = result
elif len(result) == 3: elif len(result) == 3:
self._custom_component, self._built_object, self.artifacts = result self._custom_component, self._built_object, self.artifacts = result
self.artifacts_raw = self.artifacts.get("raw", None)
self.artifacts_type = self.artifacts.get("type", None) or ArtifactType.UNKNOWN.value
else: else:
self._built_object = result self._built_object = result
@ -687,6 +694,7 @@ class Vertex:
self, self,
user_id=None, user_id=None,
inputs: Optional[Dict[str, Any]] = None, inputs: Optional[Dict[str, Any]] = None,
files: Optional[list[str]] = None,
requester: Optional["Vertex"] = None, requester: Optional["Vertex"] = None,
**kwargs, **kwargs,
) -> Any: ) -> Any:
@ -704,9 +712,14 @@ class Vertex:
return await self.get_requester_result(requester) return await self.get_requester_result(requester)
self._reset() self._reset()
if self._is_chat_input() and inputs: if self._is_chat_input() and (inputs or files):
inputs = {"input_value": inputs.get(INPUT_FIELD_NAME, "")} chat_input = {}
self.update_raw_params(inputs, overwrite=True) if inputs:
chat_input.update({"input_value": inputs.get(INPUT_FIELD_NAME, "")})
if files:
chat_input.update({"files": files})
self.update_raw_params(chat_input, overwrite=True)
# Run steps # Run steps
for step in self.steps: for step in self.steps:

View file

@ -1,13 +1,12 @@
import json import json
from typing import Any, AsyncIterator, Dict, Iterator, List from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, Iterator, List
import yaml import yaml
from git import TYPE_CHECKING
from langchain_core.messages import AIMessage, AIMessageChunk from langchain_core.messages import AIMessage, AIMessageChunk
from loguru import logger from loguru import logger
from langflow.graph.schema import CHAT_COMPONENTS, RECORDS_COMPONENTS, InterfaceComponentTypes from langflow.graph.schema import CHAT_COMPONENTS, RECORDS_COMPONENTS, InterfaceComponentTypes
from langflow.graph.utils import UnbuiltObject, serialize_field from langflow.graph.utils import ArtifactType, UnbuiltObject, serialize_field
from langflow.graph.vertex.base import Vertex from langflow.graph.vertex.base import Vertex
from langflow.graph.vertex.utils import log_transaction from langflow.graph.vertex.utils import log_transaction
from langflow.schema import Record from langflow.schema import Record
@ -153,6 +152,7 @@ class InterfaceVertex(ComponentVertex):
sender = self.params.get("sender", None) sender = self.params.get("sender", None)
sender_name = self.params.get("sender_name", None) sender_name = self.params.get("sender_name", None)
message = self.params.get(INPUT_FIELD_NAME, None) message = self.params.get(INPUT_FIELD_NAME, None)
files = [{"path": file} if isinstance(file, str) else file for file in self.params.get("files", [])]
if isinstance(message, str): if isinstance(message, str):
message = unescape_string(message) message = unescape_string(message)
stream_url = None stream_url = None
@ -182,12 +182,14 @@ class InterfaceVertex(ComponentVertex):
# it means that it is a stream of messages # it means that it is a stream of messages
else: else:
message = text_output message = text_output
artifact_type = ArtifactType.STREAM if stream_url is not None else ArtifactType.OBJECT
artifacts = ChatOutputResponse( artifacts = ChatOutputResponse(
message=message, message=message,
sender=sender, sender=sender,
sender_name=sender_name, sender_name=sender_name,
stream_url=stream_url, stream_url=stream_url,
files=files,
type=artifact_type,
) )
self.will_stream = stream_url is not None self.will_stream = stream_url is not None
@ -269,6 +271,8 @@ class InterfaceVertex(ComponentVertex):
message=complete_message, message=complete_message,
sender=self.params.get("sender", ""), sender=self.params.get("sender", ""),
sender_name=self.params.get("sender_name", ""), sender_name=self.params.get("sender_name", ""),
files=[{"path": file} if isinstance(file, str) else file for file in self.params.get("files", [])],
type=ArtifactType.OBJECT.value,
).model_dump() ).model_dump()
self.params[INPUT_FIELD_NAME] = complete_message self.params[INPUT_FIELD_NAME] = complete_message
self._built_object = Record(text=complete_message, data=self.artifacts) self._built_object = Record(text=complete_message, data=self.artifacts)

View file

@ -1,9 +1,5 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from loguru import logger
from langflow.services.deps import get_monitor_service
if TYPE_CHECKING: if TYPE_CHECKING:
from langflow.graph.vertex.base import Vertex from langflow.graph.vertex.base import Vertex
@ -21,34 +17,3 @@ def build_clean_params(target: "Vertex") -> dict:
if isinstance(value, list): if isinstance(value, list):
params[key] = [item for item in value if isinstance(item, (str, int, bool, float, list, dict))] params[key] = [item for item in value if isinstance(item, (str, int, bool, float, list, dict))]
return params return params
def log_transaction(source: "Vertex", target: "Vertex", flow_id, status, error=None):
"""
Logs a transaction between two vertices.
Args:
source (Vertex): The source vertex of the transaction.
target (Vertex): The target vertex of the transaction.
status: The status of the transaction.
error (Optional): Any error associated with the transaction.
Raises:
Exception: If there is an error while logging the transaction.
"""
try:
monitor_service = get_monitor_service()
clean_params = build_clean_params(target)
data = {
"source": source.vertex_type,
"target": target.vertex_type,
"target_args": clean_params,
"timestamp": monitor_service.get_timestamp(),
"status": status,
"error": error,
"flow_id": flow_id,
}
monitor_service.add_row(table_name="transactions", data=data)
except Exception as e:
logger.error(f"Error logging transaction: {e}")

View file

@ -1,3 +1,3 @@
from .record import docs_to_records, records_to_text from .record import docs_to_records, records_to_text, messages_to_text
__all__ = ["docs_to_records", "records_to_text"] __all__ = ["docs_to_records", "records_to_text", "messages_to_text"]

View file

@ -6,7 +6,8 @@ from pydantic.v1 import BaseModel, Field, create_model
from sqlmodel import Session, select from sqlmodel import Session, select
from langflow.graph.schema import RunOutputs from langflow.graph.schema import RunOutputs
from langflow.schema.schema import INPUT_FIELD_NAME, Record from langflow.schema import Record
from langflow.schema.schema import INPUT_FIELD_NAME
from langflow.services.database.models.flow import Flow from langflow.services.database.models.flow import Flow
from langflow.services.deps import get_session, get_settings_service, session_scope from langflow.services.deps import get_session, get_settings_service, session_scope
@ -259,3 +260,24 @@ def get_flow_by_id_or_endpoint_name(
raise HTTPException(status_code=404, detail=f"Flow identifier {flow_id_or_name} not found") raise HTTPException(status_code=404, detail=f"Flow identifier {flow_id_or_name} not found")
return flow return flow
def generate_unique_flow_name(flow_name, user_id, session):
original_name = flow_name
n = 1
while True:
# Check if a flow with the given name exists
existing_flow = session.exec(
select(Flow).where(
Flow.name == flow_name,
Flow.user_id == user_id,
)
).first()
# If no flow with the given name exists, return the name
if not existing_flow:
return flow_name
# If a flow with the name already exists, append (n) to the name and increment n
flow_name = f"{original_name} ({n})"
n += 1

View file

@ -0,0 +1,23 @@
from langflow.services.database.models.folder.model import Folder
from sqlalchemy import select
def generate_unique_folder_name(folder_name, user_id, session):
original_name = folder_name
n = 1
while True:
# Check if a folder with the given name exists
existing_folder = session.exec(
select(Folder).where(
Folder.name == folder_name,
Folder.user_id == user_id,
)
).first()
# If no folder with the given name exists, return the name
if not existing_folder:
return folder_name
# If a folder with the name already exists, append (n) to the name and increment n
folder_name = f"{original_name} ({n})"
n += 1

View file

@ -1,7 +1,9 @@
from typing import Union from typing import Union
from langchain_core.documents import Document from langchain_core.documents import Document
from langflow.schema import Record from langflow.schema import Record
from langflow.schema.message import Message
def docs_to_records(documents: list[Document]) -> list[Record]: def docs_to_records(documents: list[Document]) -> list[Record]:
@ -27,7 +29,7 @@ def records_to_text(template: str, records: Union[Record, list[Record]]) -> str:
Returns: Returns:
list[str]: The converted list of texts. list[str]: The converted list of texts.
""" """
if isinstance(records, Record): if isinstance(records, (Record)):
records = [records] records = [records]
# Check if there are any format strings in the template # Check if there are any format strings in the template
_records = [] _records = []
@ -39,3 +41,27 @@ def records_to_text(template: str, records: Union[Record, list[Record]]) -> str:
formated_records = [template.format(data=record.data, **record.data) for record in _records] formated_records = [template.format(data=record.data, **record.data) for record in _records]
return "\n".join(formated_records) return "\n".join(formated_records)
def messages_to_text(template: str, messages: Union[Message, list[Message]]) -> str:
"""
Converts a list of Messages to a list of texts.
Args:
messages (list[Message]): The list of Messages to convert.
Returns:
list[str]: The converted list of texts.
"""
if isinstance(messages, (Message)):
messages = [messages]
# Check if there are any format strings in the template
_messages = []
for message in messages:
# If it is not a message, create one with the key "text"
if not isinstance(message, Message):
raise ValueError("All elements in the list must be of type Message.")
_messages.append(message)
formated_messages = [template.format(data=message.model_dump(), **message.model_dump()) for message in _messages]
return "\n".join(formated_messages)

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Some files were not shown because too many files have changed in this diff Show more