Skip to content

Commit

Permalink
Merge branch 'main' into feat/maritaca-model-update
Browse files Browse the repository at this point in the history
  • Loading branch information
viniciossilva3 authored Mar 12, 2025
2 parents c1d49ba + eedef1e commit a11aca4
Show file tree
Hide file tree
Showing 66 changed files with 1,661 additions and 354 deletions.
129 changes: 129 additions & 0 deletions docs/docs/Concepts/concepts-flows.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,135 @@ If you've already got a Langflow JSON file, import it into Langflow by clicking

Once imported, your flow is ready to use.

:::tip
You can drag and drop Langflow JSON files directly from your file system into the Langflow window to import a flow, even into the initial Langflow splash screen.
:::

## Export Flow

The option to export a flow is available in the same menu as shown above. Once exported as JSON, you can import your flow into another Langflow instance.

## Langflow JSON file contents

Langflow JSON files contain [nodes](#nodes) and [edges](#edges) that describe components and connections, and [additional metadata](#additional-metadata-and-project-information) that describe the flow.

For an example Langflow JSON file, examine the [Basic Prompting.json](https://github.com/langflow-ai/langflow/blob/main/src/backend/base/langflow/initial_setup/starter_projects/Basic%20Prompting.json) file in the Langflow repository.

### Nodes

**Nodes** represent the components that make up the flow.

The `ChatInput` node is the entry point of the flow. It's the first node that will be executed.

`ChatInput-jFwUm` is a unique identifier for the node.

```json
{
"data": {
"description": "Get chat inputs from the Playground.",
"display_name": "Chat Input",
"id": "ChatInput-jFwUm",
"node": {
"base_classes": ["Message"],
"description": "Get chat inputs from the Playground.",
"display_name": "Chat Input",
"icon": "MessagesSquare",
"template": {
"input_value": {
"display_name": "Text",
"info": "Message to be passed as input.",
"value": "Hello"
},
"sender": {
"value": "User",
"options": ["Machine", "User"]
},
"sender_name": {
"value": "User"
},
"should_store_message": {
"value": true
}
}
},
"type": "ChatInput"
},
"position": {
"x": 689.5720422421635,
"y": 765.155834131403
}
}
```

### Edges

**Edges** represent the connections between nodes.

The connection between the `ChatInput` node and the `OpenAIModel` node is represented as an edge:

```json
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "ChatInput",
"id": "ChatInput-jFwUm",
"name": "message",
"output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-OcXkl",
"inputTypes": ["Message"],
"type": "str"
}
},
"id": "reactflow__edge-ChatInput-jFwUm{œdataTypeœ:œChatInputœ,œidœ:œChatInput-jFwUmœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-OcXkl{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-OcXklœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"source": "ChatInput-jFwUm",
"sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-jFwUmœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
"target": "OpenAIModel-OcXkl",
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-OcXklœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
}
```

This edge shows that the `ChatInput` component outputs a `Message` type to the `target` node, which is the `OpenAIModel` node.
The `OpenAIModel` component accepts the `Message` type at the `input_value` field.

### Additional metadata and project information

Additional information about the flow is stored in the root `data` object.

* Metadata and project information including the name, description, and `last_tested_version` of the flow.
```json
{
"name": "Basic Prompting",
"description": "Perform basic prompting with an OpenAI model.",
"tags": ["chatbots"],
"id": "1511c230-d446-43a7-bfc3-539e69ce05b8",
"last_tested_version": "1.0.19.post2",
"gradient": "2",
"icon": "Braces"
}
```

* Visual information about the flow defining the initial position of the flow in the workspace.
```json
"viewport": {
"x": -37.61270157375441,
"y": -155.91266341888854,
"zoom": 0.7575251406952855
}
```

**Notes** are like comments to help you understand the flow within the workspace.
They may contain links, code snippets, and other information.
Notes are written in Markdown and stored as `node` objects.
```json
{
"id": "undefined-kVLkG",
"node": {
"description": "## 📖 README\nPerform basic prompting with an OpenAI model.\n\n#### Quick Start\n- Add your **OpenAI API key** to the **OpenAI Model**\n- Open the **Playground** to chat with your bot.\n..."
}
}
```

114 changes: 114 additions & 0 deletions docs/docs/Contributing/contributing-component-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
title: Contribute component tests
slug: /contributing-component-tests
---

This guide outlines how to structure and implement tests for application components to ensure consistency and adequate coverage.

## File naming

* The test file should follow the same directory structure as the component being tested, but should be placed in the corresponding unit tests folder.

For example, if the file path for the component is `src/backend/base/langflow/components/prompts/`, then the test file should be located at `src/backend/tests/unit/components/prompts`.

* The test file name should use snake case and follow the pattern `test_<file_name>.py`.

For example, if the file to be tested is `PromptComponent.py`, then the test file should be named `test_prompt_component.py`.

## File structure

* Each test file should group tests into classes by component. There should be no standalone test functions in the file— only test methods within classes.
* Class names should follow the pattern `Test<ClassName>`.
For example, if the component being tested is `PromptComponent`, then the test class should be named `TestPromptComponent`.

## Imports, inheritance, and mandatory methods

To standardize comoponent tests, base test classes have been created and should be imported and inherited by all component test classes. These base classes are located in the file `src/backend/tests/unit/base.py`.

To import the base test classes:

```python
from tests.base import ComponentTestBaseWithClient
from tests.base import ComponentTestBaseWithoutClient
```

These base classes enforce mandatory methods that the component test classes must implement. The base classes ensure that components built in previous versions continues to work in the current version. By inheriting from one of these base classes, the developer must define the following methods decorated with `@pytest.fixture`:

* `component_class:` Returns the class of the component to be tested. For example:

```python
@pytest.fixture
def component_class(self):
return PromptComponent
```

* `default_kwargs:` Returns a dictionary with the default arguments required to instantiate the component. For example:

```python
@pytest.fixture
def default_kwargs(self):
return {"template": "Hello {name}!", "name": "John", "_session_id": "123"}
```

* `file_names_mapping:` Returns a list of dictionaries representing the relationship between `version`, `module`, and `file_name` that the tested component has had over time. This can be left empty if it is an unreleased component. For example:

```python
@pytest.fixture
def file_names_mapping(self):
return [
{"version": "1.0.15", "module": "prompts", "file_name": "Prompt"},
{"version": "1.0.16", "module": "prompts", "file_name": "Prompt"},
{"version": "1.0.17", "module": "prompts", "file_name": "Prompt"},
{"version": "1.0.18", "module": "prompts", "file_name": "Prompt"},
{"version": "1.0.19", "module": "prompts", "file_name": "Prompt"},
]
```

## Testing component functionalities

Once the basic structure of the test file is defined, implement test methods for the component's functionalities. The following guidelines must be followed:

1. Test method names should be descriptive, use snake case, and follow the pattern `test_<case_name>`.
2. Each test should follow the **Arrange, Act, Assert** pattern:
1. **Arrange**: Prepare the data.
2. **Act**: Execute the component.
3. **Assert**: Verify the result.

### Example

1. **Arrange**: Prepare the data.

It is **recommended** to use the fixtures defined in the basic structure, but not mandatory.

```python
def test_post_code_processing(self, component_class, default_kwargs):
component = component_class(**default_kwargs)
```

2. **Act**: Execute the component.

Call the `.to_frontend_node()` method of the component prepared during the **Arrange** step.

```python
def test_post_code_processing(self, component_class, default_kwargs):
component = component_class(**default_kwargs)

frontend_node = component.to_frontend_node()
```

3. **Assert**: Verify the result.

After executing the `.to_frontend_node()` method, the resulting data is available for verification in the dictionary `frontend_node["data"]["node"]`. Assertions should be clear and cover the expected outcomes.

```python
def test_post_code_processing(self, component_class, default_kwargs):
component = component_class(**default_kwargs)

frontend_node = component.to_frontend_node()

node_data = frontend_node["data"]["node"]
assert node_data["template"]["template"]["value"] == "Hello {name}!"
assert "name" in node_data["custom_fields"]["template"]
assert "name" in node_data["template"]
assert node_data["template"]["name"]["value"] == "John"
```
24 changes: 24 additions & 0 deletions docs/docs/Support/luna-for-langflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: Luna for Langflow
slug: /luna-for-langflow
---

With [Luna for Langflow](https://www.datastax.com/products/luna-langflow) support, you can develop and deploy Langflow applications with confidence.

**Luna** is a subscription to the Langflow expertise at DataStax. It's meant for users of Langflow who want all the benefits of running their own open-source deployments, but with the peace of mind that comes with having direct access to the team that has authored the majority of the Langflow code.

**Luna** subscribers can get help with general-purpose and technical questions for their open-source Langflow deployments, and if an issue is encountered, DataStax is there to help.

Ready to subscribe?

Visit the [Luna for Langflow](https://www.datastax.com/products/luna-langflow) product page to get started.

## Supported software

Luna for Langflow support covers only the following software versions for Langflow.

Last updated: 2025-03-11

## Core information
- **Langflow Version**: `1.2.0`
- **Python Version Required**: `>=3.10, <3.14`
2 changes: 1 addition & 1 deletion docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const config = {
"Langflow is a low-code app builder for RAG and multi-agent AI applications.",
favicon: "img/favicon.ico",
url: "https://docs.langflow.org",
baseUrl: "/",
baseUrl: process.env.BASE_URL ? process.env.BASE_URL : "/",
onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn",
onBrokenAnchors: "warn",
Expand Down
12 changes: 12 additions & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ module.exports = {
items: [
"Contributing/contributing-community",
"Contributing/contributing-components",
"Contributing/contributing-component-tests",
"Contributing/contributing-github-discussion-board",
"Contributing/contributing-github-issues",
"Contributing/contributing-how-to-contribute",
Expand All @@ -196,5 +197,16 @@ module.exports = {
},
],
},
{
type: "category",
label: "Support",
items: [
{
type: "doc",
id: "Support/luna-for-langflow",
label: "Luna for Langflow",
},
],
},
],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Add column fs_path to Flow
Revision ID: 93e2705fa8d6
Revises: dd9e0804ebd1
Create Date: 2025-02-25 13:08:11.263504
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
import sqlmodel
from sqlalchemy.engine.reflection import Inspector
from langflow.utils import migration


# revision identifiers, used by Alembic.
revision: str = '93e2705fa8d6'
down_revision: Union[str, None] = 'dd9e0804ebd1'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
conn = op.get_bind()
inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ###
column_names = [column["name"] for column in inspector.get_columns("flow")]
with op.batch_alter_table("flow", schema=None) as batch_op:
if "fs_path" not in column_names:
batch_op.add_column(sa.Column("fs_path", sqlmodel.sql.sqltypes.AutoString(), nullable=True))

# ### end Alembic commands ###


def downgrade() -> None:
conn = op.get_bind()
inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ###
column_names = [column["name"] for column in inspector.get_columns("flow")]
with op.batch_alter_table("flow", schema=None) as batch_op:
if "fs_path" in column_names:
batch_op.drop_column("fs_path")
13 changes: 6 additions & 7 deletions src/backend/base/langflow/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,12 @@ def has_api_terms(word: str):

def remove_api_keys(flow: dict):
"""Remove api keys from flow data."""
if flow.get("data") and flow["data"].get("nodes"):
for node in flow["data"]["nodes"]:
node_data = node.get("data").get("node")
template = node_data.get("template")
for value in template.values():
if isinstance(value, dict) and has_api_terms(value["name"]) and value.get("password"):
value["value"] = None
for node in flow.get("data", {}).get("nodes", []):
node_data = node.get("data").get("node")
template = node_data.get("template")
for value in template.values():
if isinstance(value, dict) and has_api_terms(value["name"]) and value.get("password"):
value["value"] = None

return flow

Expand Down
Loading

0 comments on commit a11aca4

Please sign in to comment.