diff --git a/src/backend/base/langflow/alembic/versions/1eab2c3eb45e_event_error.py b/src/backend/base/langflow/alembic/versions/1eab2c3eb45e_event_error.py
new file mode 100644
index 000000000..7647a7173
--- /dev/null
+++ b/src/backend/base/langflow/alembic/versions/1eab2c3eb45e_event_error.py
@@ -0,0 +1,53 @@
+"""event_error
+
+Revision ID: 1eab2c3eb45e
+Revises: eb5e72293a8e
+Create Date: 2024-10-24 12:03:24.118937
+
+"""
+from typing import Sequence, Union
+
+import sqlalchemy as sa
+from alembic import op
+from sqlalchemy.dialects import sqlite
+from sqlalchemy.engine.reflection import Inspector
+
+# revision identifiers, used by Alembic.
+revision: str = '1eab2c3eb45e'
+down_revision: Union[str, None] = 'eb5e72293a8e'
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+ conn = op.get_bind()
+ inspector = Inspector.from_engine(conn) # type: ignore
+ table_names = inspector.get_table_names() # noqa
+ column_names = [column["name"] for column in inspector.get_columns("message")]
+ # ### commands auto generated by Alembic - please adjust! ###
+ with op.batch_alter_table('message', schema=None) as batch_op:
+ if "properties" not in column_names:
+ batch_op.add_column(sa.Column('properties', sa.JSON(), nullable=True))
+ if "category" not in column_names:
+ batch_op.add_column(sa.Column('category', sa.Text(), nullable=True))
+ if "content_blocks" not in column_names:
+ batch_op.add_column(sa.Column('content_blocks', sa.JSON(), nullable=True))
+
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ conn = op.get_bind()
+ inspector = Inspector.from_engine(conn) # type: ignore
+ table_names = inspector.get_table_names() # noqa
+ column_names = [column["name"] for column in inspector.get_columns("message")]
+ # ### commands auto generated by Alembic - please adjust! ###
+ with op.batch_alter_table('message', schema=None) as batch_op:
+ if "content_blocks" in column_names:
+ batch_op.drop_column('content_blocks')
+ if "category" in column_names:
+ batch_op.drop_column('category')
+ if "properties" in column_names:
+ batch_op.drop_column('properties')
+
+ # ### end Alembic commands ###
diff --git a/src/backend/base/langflow/api/v1/chat.py b/src/backend/base/langflow/api/v1/chat.py
index 742c1baea..ce7dfc579 100644
--- a/src/backend/base/langflow/api/v1/chat.py
+++ b/src/backend/base/langflow/api/v1/chat.py
@@ -177,6 +177,9 @@ async def build_flow(
else:
first_layer = graph.sort_vertices()
+ if inputs is not None and hasattr(inputs, "session") and inputs.session is not None:
+ graph.session_id = inputs.session
+
for vertex_id in first_layer:
graph.run_manager.add_to_vertices_being_run(vertex_id)
diff --git a/src/backend/base/langflow/base/agents/callback.py b/src/backend/base/langflow/base/agents/callback.py
index b1a1a3f33..1ff6d2c04 100644
--- a/src/backend/base/langflow/base/agents/callback.py
+++ b/src/backend/base/langflow/base/agents/callback.py
@@ -13,6 +13,33 @@ class AgentAsyncHandler(AsyncCallbackHandler):
def __init__(self, log_function: LogFunctionType | None = None):
self.log_function = log_function
+ async def on_chain_start(
+ self,
+ serialized: dict[str, Any],
+ inputs: dict[str, Any],
+ *,
+ run_id: UUID,
+ parent_run_id: UUID | None = None,
+ tags: list[str] | None = None,
+ metadata: dict[str, Any] | None = None,
+ **kwargs: Any,
+ ) -> None:
+ if self.log_function is None:
+ return
+ self.log_function(
+ {
+ "type": "chain_start",
+ "serialized": serialized,
+ "inputs": inputs,
+ "run_id": run_id,
+ "parent_run_id": parent_run_id,
+ "tags": tags,
+ "metadata": metadata,
+ **kwargs,
+ },
+ name="Chain Start",
+ )
+
async def on_tool_start(
self,
serialized: dict[str, Any],
diff --git a/src/backend/base/langflow/base/io/chat.py b/src/backend/base/langflow/base/io/chat.py
index 836a827d0..559058608 100644
--- a/src/backend/base/langflow/base/io/chat.py
+++ b/src/backend/base/langflow/base/io/chat.py
@@ -1,86 +1,15 @@
-from collections.abc import AsyncIterator, Iterator
from typing import cast
from langflow.custom import Component
from langflow.memory import store_message
from langflow.schema import Data
from langflow.schema.message import Message
-from langflow.services.database.models.message.crud import update_message
-from langflow.utils.async_helpers import run_until_complete
class ChatComponent(Component):
display_name = "Chat Component"
description = "Use as base for chat components."
- def store_message(self, message: Message) -> Message:
- messages = store_message(message, flow_id=self.graph.flow_id)
- if len(messages) != 1:
- msg = "Only one message can be stored at a time."
- raise ValueError(msg)
-
- stored_message = messages[0]
- self._send_message_event(stored_message)
-
- if self._should_stream_message(stored_message, message):
- complete_message = self._stream_message(message, stored_message.id)
- stored_message = self._update_stored_message(stored_message.id, complete_message)
-
- self.status = stored_message
- return stored_message
-
- def _send_message_event(self, message: Message) -> None:
- if hasattr(self, "_event_manager") and self._event_manager:
- self._event_manager.on_message(data=message.data)
-
- def _should_stream_message(self, stored_message: Message, original_message: Message) -> bool:
- return bool(
- hasattr(self, "_event_manager")
- and self._event_manager
- and stored_message.id
- and not isinstance(original_message.text, str)
- )
-
- def _update_stored_message(self, message_id: str, complete_message: str) -> Message:
- message_table = update_message(message_id=message_id, message={"text": complete_message})
- updated_message = Message(**message_table.model_dump())
- self.vertex.added_message = updated_message
- return updated_message
-
- def _process_chunk(self, chunk: str, complete_message: str, message: Message, message_id: str) -> str:
- complete_message += chunk
- if self._event_manager:
- self._event_manager.on_token(
- data={
- "text": complete_message,
- "chunk": chunk,
- "sender": message.sender,
- "sender_name": message.sender_name,
- "id": str(message_id),
- }
- )
- return complete_message
-
- async def _handle_async_iterator(self, iterator: AsyncIterator, message: Message, message_id: str) -> str:
- complete_message = ""
- async for chunk in iterator:
- complete_message = self._process_chunk(chunk.content, complete_message, message, message_id)
- return complete_message
-
- def _stream_message(self, message: Message, message_id: str) -> str:
- iterator = message.text
- if not isinstance(iterator, AsyncIterator | Iterator):
- msg = "The message must be an iterator or an async iterator."
- raise TypeError(msg)
-
- if isinstance(iterator, AsyncIterator):
- return run_until_complete(self._handle_async_iterator(iterator, message, message_id))
-
- complete_message = ""
- for chunk in iterator:
- complete_message = self._process_chunk(chunk.content, complete_message, message, message_id)
- return complete_message
-
def build_with_data(
self,
*,
@@ -105,9 +34,31 @@ class ChatComponent(Component):
def _create_message(self, input_value, sender, sender_name, files, session_id) -> Message:
if isinstance(input_value, Data):
return Message.from_data(input_value)
- return Message(text=input_value, sender=sender, sender_name=sender_name, files=files, session_id=session_id)
+ return Message(
+ text=input_value,
+ sender=sender,
+ sender_name=sender_name,
+ files=files,
+ session_id=session_id,
+ category="message",
+ )
def _send_messages_events(self, messages) -> None:
if hasattr(self, "_event_manager") and self._event_manager:
for stored_message in messages:
- self._event_manager.on_message(data=stored_message.data)
+ id_ = stored_message.id
+ self._send_message_event(message=stored_message, id_=id_)
+
+ def get_properties_from_source_component(self):
+ if self.vertex.incoming_edges:
+ source_id = self.vertex.incoming_edges[0].source_id
+ _source_vertex = self.graph.get_vertex(source_id)
+ component = _source_vertex.custom_component
+ source = component.display_name
+ icon = component.icon
+ possible_attributes = ["model_name", "model_id", "model"]
+ for attribute in possible_attributes:
+ if hasattr(component, attribute) and getattr(component, attribute):
+ return getattr(component, attribute), icon, source, component._id
+ return source, icon, component.display_name, component._id
+ return None, None, None, None
diff --git a/src/backend/base/langflow/components/inputs/chat.py b/src/backend/base/langflow/components/inputs/chat.py
index f52efbab1..be8e656cf 100644
--- a/src/backend/base/langflow/components/inputs/chat.py
+++ b/src/backend/base/langflow/components/inputs/chat.py
@@ -55,21 +55,43 @@ class ChatInput(ChatComponent):
advanced=True,
is_list=True,
),
+ MessageTextInput(
+ name="background_color",
+ display_name="Background Color",
+ info="The background color of the icon.",
+ advanced=True,
+ ),
+ MessageTextInput(
+ name="chat_icon",
+ display_name="Icon",
+ info="The icon of the message.",
+ advanced=True,
+ ),
+ MessageTextInput(
+ name="text_color",
+ display_name="Text Color",
+ info="The text color of the name",
+ advanced=True,
+ ),
]
outputs = [
Output(display_name="Message", name="message", method="message_response"),
]
def message_response(self) -> Message:
+ _background_color = self.background_color
+ _text_color = self.text_color
+ _icon = self.chat_icon
message = Message(
text=self.input_value,
sender=self.sender,
sender_name=self.sender_name,
session_id=self.session_id,
files=self.files,
+ properties={"background_color": _background_color, "text_color": _text_color, "icon": _icon},
)
if self.session_id and isinstance(message, Message) and self.should_store_message:
- stored_message = self.store_message(
+ stored_message = self.send_message(
message,
)
self.message.value = stored_message
diff --git a/src/backend/base/langflow/components/outputs/chat.py b/src/backend/base/langflow/components/outputs/chat.py
index 0493a28b5..20bad1a33 100644
--- a/src/backend/base/langflow/components/outputs/chat.py
+++ b/src/backend/base/langflow/components/outputs/chat.py
@@ -2,6 +2,7 @@ from langflow.base.io.chat import ChatComponent
from langflow.inputs import BoolInput
from langflow.io import DropdownInput, MessageTextInput, Output
from langflow.schema.message import Message
+from langflow.schema.properties import Properties, Source
from langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER
@@ -52,20 +53,64 @@ class ChatOutput(ChatComponent):
advanced=True,
info="Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
),
+ MessageTextInput(
+ name="background_color",
+ display_name="Background Color",
+ info="The background color of the icon.",
+ advanced=True,
+ ),
+ MessageTextInput(
+ name="chat_icon",
+ display_name="Icon",
+ info="The icon of the message.",
+ advanced=True,
+ ),
+ MessageTextInput(
+ name="text_color",
+ display_name="Text Color",
+ info="The text color of the name",
+ advanced=True,
+ ),
]
outputs = [
- Output(display_name="Message", name="message", method="message_response"),
+ Output(
+ display_name="Message",
+ name="message",
+ method="message_response",
+ ),
]
+ def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:
+ source_dict = {}
+ if _id:
+ source_dict["id"] = _id
+ if display_name:
+ source_dict["display_name"] = display_name
+ if source:
+ source_dict["source"] = source
+ return Source(**source_dict)
+
def message_response(self) -> Message:
+ _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()
+ _background_color = self.background_color
+ _text_color = self.text_color
+ if self.chat_icon:
+ _icon = self.chat_icon
message = Message(
text=self.input_value,
sender=self.sender,
sender_name=self.sender_name,
session_id=self.session_id,
+ flow_id=self.graph.flow_id,
+ properties=Properties(
+ source=self._build_source(_source_id, _display_name, _source),
+ icon=_icon,
+ background_color=_background_color,
+ text_color=_text_color,
+ ),
)
if self.session_id and isinstance(message, Message) and self.should_store_message:
- stored_message = self.store_message(
+ stored_message = self.send_message(
message,
)
self.message.value = stored_message
diff --git a/src/backend/base/langflow/custom/custom_component/component.py b/src/backend/base/langflow/custom/custom_component/component.py
index 22db8d35e..8f6e2e9ea 100644
--- a/src/backend/base/langflow/custom/custom_component/component.py
+++ b/src/backend/base/langflow/custom/custom_component/component.py
@@ -3,6 +3,7 @@ from __future__ import annotations
import ast
import asyncio
import inspect
+from collections.abc import AsyncIterator, Iterator
from copy import deepcopy
from textwrap import dedent
from typing import TYPE_CHECKING, Any, ClassVar, get_type_hints
@@ -13,12 +14,15 @@ from pydantic import BaseModel, ValidationError
from langflow.base.tools.constants import TOOL_OUTPUT_NAME
from langflow.custom.tree_visitor import RequiredInputsVisitor
+from langflow.exceptions.component import StreamingError
from langflow.field_typing import Tool # noqa: TCH001 Needed by _add_toolkit_output
from langflow.graph.state.model import create_state_model
from langflow.helpers.custom import format_type
+from langflow.memory import delete_message, store_message, update_messages
from langflow.schema.artifact import get_artifact_type, post_process_raw
from langflow.schema.data import Data
-from langflow.schema.message import Message
+from langflow.schema.message import ErrorMessage, Message
+from langflow.schema.properties import Source
from langflow.services.settings.feature_flags import FEATURE_FLAGS
from langflow.services.tracing.schema import Log
from langflow.template.field.base import UNDEFINED, Input, Output
@@ -59,7 +63,7 @@ class Component(CustomComponent):
inputs: list[InputTypes] = []
outputs: list[Output] = []
code_class_base_inheritance: ClassVar[str] = "Component"
- _output_logs: dict[str, Log] = {}
+ _output_logs: dict[str, list[Log]] = {}
_current_output: str = ""
_metadata: dict = {}
@@ -736,14 +740,30 @@ class Component(CustomComponent):
async def _build_without_tracing(self):
return await self._build_results()
- async def build_results(
- self,
- ):
- if self._tracing_service:
- return await self._build_with_tracing()
- return await self._build_without_tracing()
+ async def build_results(self):
+ """Build the results of the component."""
+ try:
+ if self._tracing_service:
+ return await self._build_with_tracing()
+ return await self._build_without_tracing()
+ except StreamingError as e:
+ self.send_error(
+ exception=e.cause,
+ session_id=self.graph.session_id,
+ trace_name=getattr(self, "trace_name", None),
+ source=e.source,
+ )
+ raise e.cause # noqa: B904
+ except Exception as e:
+ self.send_error(
+ exception=e,
+ session_id=self.graph.session_id,
+ source=Source(id=self._id, display_name=self.display_name, source=self.display_name),
+ trace_name=getattr(self, "trace_name", None),
+ )
+ raise
- async def _build_results(self):
+ async def _build_results(self) -> tuple[dict, dict]:
_results = {}
_artifacts = {}
if hasattr(self, "outputs"):
@@ -881,3 +901,132 @@ class Component(CustomComponent):
def _append_tool_output(self) -> None:
if next((output for output in self.outputs if output.name == TOOL_OUTPUT_NAME), None) is None:
self.outputs.append(Output(name=TOOL_OUTPUT_NAME, display_name="Tool", method="to_toolkit", types=["Tool"]))
+
+ def send_message(self, message: Message, id_: str | None = None):
+ if self.graph.session_id and message is not None and message.session_id is None:
+ message.session_id = self.graph.session_id
+ stored_message = self._store_message(message)
+
+ self._stored_message_id = stored_message.id
+ try:
+ complete_message = ""
+ if (
+ self._should_stream_message(stored_message, message)
+ and message is not None
+ and isinstance(message.text, AsyncIterator | Iterator)
+ ):
+ complete_message = self._stream_message(message.text, stored_message)
+ stored_message.text = complete_message
+ stored_message = self._update_stored_message(stored_message)
+ else:
+ # Only send message event for non-streaming messages
+ self._send_message_event(stored_message, id_=id_)
+ except Exception:
+ # remove the message from the database
+ delete_message(stored_message.id)
+ raise
+ self.status = stored_message
+ return stored_message
+
+ def _store_message(self, message: Message) -> Message:
+ messages = store_message(message, flow_id=self.graph.flow_id)
+ if len(messages) != 1:
+ msg = "Only one message can be stored at a time."
+ raise ValueError(msg)
+
+ return messages[0]
+
+ def _send_message_event(self, message: Message, id_: str | None = None):
+ if hasattr(self, "_event_manager") and self._event_manager:
+ data_dict = message.data.copy() if hasattr(message, "data") else message.model_dump()
+ if id_ and not data_dict.get("id"):
+ data_dict["id"] = id_
+ category = data_dict.get("category", None)
+ match category:
+ case "error":
+ self._event_manager.on_error(data=data_dict)
+ case _:
+ self._event_manager.on_message(data=data_dict)
+
+ def _should_stream_message(self, stored_message: Message, original_message: Message) -> bool:
+ return bool(
+ hasattr(self, "_event_manager")
+ and self._event_manager
+ and stored_message.id
+ and not isinstance(original_message.text, str)
+ )
+
+ def _update_stored_message(self, stored_message: Message) -> Message:
+ message_tables = update_messages(stored_message)
+ if len(message_tables) != 1:
+ msg = "Only one message can be updated at a time."
+ raise ValueError(msg)
+ message_table = message_tables[0]
+ updated_message = Message(**message_table.model_dump())
+ self.vertex._added_message = updated_message
+ return updated_message
+
+ def _stream_message(self, iterator: AsyncIterator | Iterator, message: Message) -> str:
+ if not isinstance(iterator, AsyncIterator | Iterator):
+ msg = "The message must be an iterator or an async iterator."
+ raise TypeError(msg)
+
+ if isinstance(iterator, AsyncIterator):
+ return run_until_complete(self._handle_async_iterator(iterator, message.id, message))
+ try:
+ complete_message = ""
+ first_chunk = True
+ for chunk in iterator:
+ complete_message = self._process_chunk(
+ chunk.content, complete_message, message.id, message, first_chunk=first_chunk
+ )
+ first_chunk = False
+ except Exception as e:
+ raise StreamingError(cause=e, source=message.properties.source) from e
+ else:
+ return complete_message
+
+ async def _handle_async_iterator(self, iterator: AsyncIterator, message_id: str, message: Message) -> str:
+ complete_message = ""
+ first_chunk = True
+ async for chunk in iterator:
+ complete_message = self._process_chunk(
+ chunk.content, complete_message, message_id, message, first_chunk=first_chunk
+ )
+ first_chunk = False
+ return complete_message
+
+ def _process_chunk(
+ self, chunk: str, complete_message: str, message_id: str, message: Message, *, first_chunk: bool = False
+ ) -> str:
+ complete_message += chunk
+ if self._event_manager:
+ if first_chunk:
+ # Send the initial message only on the first chunk
+ msg_copy = message.model_copy()
+ msg_copy.text = complete_message
+ self._send_message_event(msg_copy, id_=message_id)
+ self._event_manager.on_token(
+ data={
+ "chunk": chunk,
+ "id": str(message_id),
+ }
+ )
+ return complete_message
+
+ def send_error(
+ self,
+ exception: Exception,
+ session_id: str,
+ trace_name: str,
+ source: Source,
+ ) -> None:
+ """Send an error message to the frontend."""
+ error_message = ErrorMessage(
+ flow_id=self.graph.flow_id,
+ exception=exception,
+ session_id=session_id,
+ trace_name=trace_name,
+ source=source,
+ )
+ self.send_message(error_message)
diff --git a/src/backend/base/langflow/custom/custom_component/custom_component.py b/src/backend/base/langflow/custom/custom_component/custom_component.py
index 7544e4243..1597c7194 100644
--- a/src/backend/base/langflow/custom/custom_component/custom_component.py
+++ b/src/backend/base/langflow/custom/custom_component/custom_component.py
@@ -83,7 +83,7 @@ class CustomComponent(BaseComponent):
_flows_data: list[Data] | None = None
_outputs: list[OutputValue] = []
_logs: list[Log] = []
- _output_logs: dict[str, Log] = {}
+ _output_logs: dict[str, list[Log] | Log] = {}
_tracing_service: TracingService | None = None
_tree: dict | None = None
@@ -93,8 +93,8 @@ class CustomComponent(BaseComponent):
Args:
**data: Additional keyword arguments to initialize the custom component.
"""
- self.cache = TTLCache(maxsize=1024, ttl=60)
- self._logs = []
+ self.cache: TTLCache = TTLCache(maxsize=1024, ttl=60)
+ self._logs: list[Log] = []
self._results: dict = {}
self._artifacts: dict = {}
super().__init__(**data)
diff --git a/src/backend/base/langflow/events/event_manager.py b/src/backend/base/langflow/events/event_manager.py
index ff1aea675..0032c61e7 100644
--- a/src/backend/base/langflow/events/event_manager.py
+++ b/src/backend/base/langflow/events/event_manager.py
@@ -4,12 +4,14 @@ import json
import time
import uuid
from functools import partial
+from typing import Literal
from fastapi.encoders import jsonable_encoder
+from loguru import logger
from typing_extensions import Protocol
-from langflow.schema.artifact import CUSTOM_ENCODERS
from langflow.schema.log import LoggableType
+from langflow.schema.playground_events import create_event_by_type
class EventCallback(Protocol):
@@ -40,7 +42,12 @@ class EventManager:
msg = "Callback must have exactly 3 parameters: manager, event_type, and data"
raise ValueError(msg)
- def register_event(self, name: str, event_type: str, callback: EventCallback | None = None) -> None:
+ def register_event(
+ self,
+ name: str,
+ event_type: Literal["message", "error", "warning", "info", "token"],
+ callback: EventCallback | None = None,
+ ) -> None:
if not name:
msg = "Event name cannot be empty"
raise ValueError(msg)
@@ -53,10 +60,17 @@ class EventManager:
_callback = partial(callback, manager=self, event_type=event_type)
self.events[name] = _callback
- def send_event(self, *, event_type: str, data: LoggableType) -> None:
- jsonable_data = jsonable_encoder(data, custom_encoder=CUSTOM_ENCODERS)
+ def send_event(self, *, event_type: Literal["message", "error", "warning", "info", "token"], data: LoggableType):
+ try:
+ if isinstance(data, dict) and event_type in ["message", "error", "warning", "info", "token"]:
+ data = create_event_by_type(event_type, **data)
+ except TypeError as e:
+ logger.debug(f"Error creating playground event: {e}")
+ except Exception:
+ raise
+ jsonable_data = jsonable_encoder(data)
json_data = {"event": event_type, "data": jsonable_data}
- event_id = uuid.uuid4()
+ event_id = f"{event_type}-{uuid.uuid4()}"
str_data = json.dumps(json_data) + "\n\n"
self.queue.put_nowait((event_id, str_data.encode("utf-8"), time.time()))
diff --git a/src/backend/base/langflow/exceptions/component.py b/src/backend/base/langflow/exceptions/component.py
index 65f8f80ff..1f61ab910 100644
--- a/src/backend/base/langflow/exceptions/component.py
+++ b/src/backend/base/langflow/exceptions/component.py
@@ -1,6 +1,17 @@
# Create an exception class that receives the message and the formatted traceback
+
+from langflow.schema.properties import Source
+
+
class ComponentBuildError(Exception):
def __init__(self, message: str, formatted_traceback: str):
self.message = message
self.formatted_traceback = formatted_traceback
super().__init__(message)
+
+
+class StreamingError(Exception):
+ def __init__(self, cause: Exception, source: Source):
+ self.cause = cause
+ self.source = source
+ super().__init__(cause)
diff --git a/src/backend/base/langflow/graph/graph/base.py b/src/backend/base/langflow/graph/graph/base.py
index 3ce41859a..af06751d2 100644
--- a/src/backend/base/langflow/graph/graph/base.py
+++ b/src/backend/base/langflow/graph/graph/base.py
@@ -93,6 +93,7 @@ class Graph:
self.has_session_id_vertices: list[str] = []
self._sorted_vertices_layers: list[list[str]] = []
self._run_id = ""
+ self._session_id = ""
self._start_time = datetime.now(timezone.utc)
self.inactivated_vertices: set = set()
self.activated_vertices: list[str] = []
@@ -134,6 +135,14 @@ class Graph:
msg = "You must provide both input and output components"
raise ValueError(msg)
+ @property
+ def session_id(self):
+ return self._session_id
+
+ @session_id.setter
+ def session_id(self, value: str):
+ self._session_id = value
+
@property
def state_model(self):
if not self._state_model:
@@ -780,7 +789,7 @@ class Graph:
Returns:
dict: The metadata of the graph.
"""
- time_format = "%Y-%m-%d %H:%M:%S"
+ time_format = "%Y-%m-%d %H:%M:%S %Z"
return {
"start_time": self._start_time.strftime(time_format),
"end_time": self._end_time.strftime(time_format),
diff --git a/src/backend/base/langflow/graph/vertex/base.py b/src/backend/base/langflow/graph/vertex/base.py
index 48853614a..cbcdfcf2a 100644
--- a/src/backend/base/langflow/graph/vertex/base.py
+++ b/src/backend/base/langflow/graph/vertex/base.py
@@ -94,7 +94,7 @@ class Vertex:
self.result: ResultData | None = None
self.results: dict[str, Any] = {}
self.outputs_logs: dict[str, OutputValue] = {}
- self.logs: dict[str, Log] = {}
+ self.logs: dict[str, list[Log]] = {}
self.has_cycle_edges = False
try:
self.is_interface_component = self.vertex_type in InterfaceComponentTypes
@@ -227,6 +227,7 @@ class Vertex:
self.output = self.data["node"]["base_classes"]
self.display_name: str = self.data["node"].get("display_name", self.id.split("-")[0])
+ self.icon: str = self.data["node"].get("icon", self.id.split("-")[0])
self.description: str = self.data["node"].get("description", "")
self.frozen: bool = self.data["node"].get("frozen", False)
@@ -803,9 +804,9 @@ class Vertex:
inputs
and isinstance(inputs, dict)
and "input_value" in inputs
- and inputs["input_value"] is not None
+ and inputs.get("input_value") is not None
):
- chat_input.update({"input_value": inputs[INPUT_FIELD_NAME]})
+ chat_input.update({"input_value": inputs.get(INPUT_FIELD_NAME, "")})
if files:
chat_input.update({"files": files})
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Agent Flow.json b/src/backend/base/langflow/initial_setup/starter_projects/Agent Flow.json
index a30d3bdd2..5da7861b4 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Agent Flow.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Agent Flow.json
@@ -159,6 +159,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -175,7 +217,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n _background_color = self.background_color\n _text_color = self.text_color\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\"background_color\": _background_color, \"text_color\": _text_color, \"icon\": _icon},\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"files": {
"_input_type": "FileInput",
@@ -318,6 +360,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
@@ -382,6 +445,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -398,7 +503,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"_input_type": "MessageTextInput",
@@ -519,6 +624,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json
index 271741b12..e4fbdc78c 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json
@@ -127,6 +127,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -143,7 +185,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n _background_color = self.background_color\n _text_color = self.text_color\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\"background_color\": _background_color, \"text_color\": _text_color, \"icon\": _icon},\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"files": {
"advanced": true,
@@ -280,6 +322,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
@@ -466,6 +529,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -482,7 +587,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"advanced": true,
@@ -597,6 +702,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json
index 07f9ad0ad..e8360e49b 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json
@@ -689,6 +689,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -705,7 +747,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"advanced": true,
@@ -820,6 +862,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Complex Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Complex Agent.json
index 14346ba2b..5b04027b6 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Complex Agent.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Complex Agent.json
@@ -1223,6 +1223,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -1239,7 +1281,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"advanced": true,
@@ -1353,6 +1395,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
@@ -2515,6 +2578,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -2531,7 +2636,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n _background_color = self.background_color\n _text_color = self.text_color\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\"background_color\": _background_color, \"text_color\": _text_color, \"icon\": _icon},\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"files": {
"advanced": true,
@@ -2667,6 +2772,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json b/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json
index a7f6e193d..40be5ce7d 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json
@@ -326,6 +326,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -342,7 +384,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n _background_color = self.background_color\n _text_color = self.text_color\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\"background_color\": _background_color, \"text_color\": _text_color, \"icon\": _icon},\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"files": {
"advanced": true,
@@ -479,6 +521,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
@@ -544,6 +607,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -560,7 +665,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"advanced": true,
@@ -675,6 +780,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Hierarchical Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Hierarchical Agent.json
index 8316145c1..cf0398c6c 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Hierarchical Agent.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Hierarchical Agent.json
@@ -927,6 +927,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -943,7 +985,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"advanced": true,
@@ -1057,6 +1099,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
@@ -2243,6 +2306,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -2259,7 +2364,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n _background_color = self.background_color\n _text_color = self.text_color\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\"background_color\": _background_color, \"text_color\": _text_color, \"icon\": _icon},\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"files": {
"advanced": true,
@@ -2395,6 +2500,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json
index fbabee675..3761499a1 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json
@@ -300,6 +300,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -316,7 +358,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n _background_color = self.background_color\n _text_color = self.text_color\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\"background_color\": _background_color, \"text_color\": _text_color, \"icon\": _icon},\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"files": {
"advanced": true,
@@ -453,6 +495,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
@@ -852,6 +915,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -868,7 +973,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"advanced": true,
@@ -983,6 +1088,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Agent.json
index 3d7b2b1cc..a9502d31a 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Agent.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Agent.json
@@ -937,6 +937,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -953,7 +995,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"advanced": true,
@@ -1067,6 +1109,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json
index 2482d8138..e27e84dd3 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json
@@ -418,6 +418,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -434,7 +476,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n _background_color = self.background_color\n _text_color = self.text_color\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\"background_color\": _background_color, \"text_color\": _text_color, \"icon\": _icon},\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"files": {
"_input_type": "FileInput",
@@ -577,6 +619,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
@@ -641,6 +704,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -657,7 +762,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"_input_type": "MessageTextInput",
@@ -778,6 +883,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json
index 95148917b..a3038c0e0 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json
@@ -310,6 +310,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -326,7 +368,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_USER, MESSAGE_SENDER_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n _background_color = self.background_color\n _text_color = self.text_color\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\"background_color\": _background_color, \"text_color\": _text_color, \"icon\": _icon},\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"files": {
"advanced": true,
@@ -462,6 +504,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
@@ -1325,6 +1388,48 @@
"pinned": false,
"template": {
"_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
"code": {
"advanced": true,
"dynamic": true,
@@ -1341,7 +1446,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.store_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Properties, Source\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, _id: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if _id:\n source_dict[\"id\"] = _id\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n def message_response(self) -> Message:\n _source, _icon, _display_name, _source_id = self.get_properties_from_source_component()\n _background_color = self.background_color\n _text_color = self.text_color\n if self.chat_icon:\n _icon = self.chat_icon\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n flow_id=self.graph.flow_id,\n properties=Properties(\n source=self._build_source(_source_id, _display_name, _source),\n icon=_icon,\n background_color=_background_color,\n text_color=_text_color,\n ),\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
},
"data_template": {
"advanced": true,
@@ -1455,6 +1560,27 @@
"trace_as_metadata": true,
"type": "bool",
"value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
}
}
},
diff --git a/src/backend/base/langflow/interface/initialize/loading.py b/src/backend/base/langflow/interface/initialize/loading.py
index aacb8e3cc..9bd831112 100644
--- a/src/backend/base/langflow/interface/initialize/loading.py
+++ b/src/backend/base/langflow/interface/initialize/loading.py
@@ -42,6 +42,7 @@ def instantiate_class(
_parameters=custom_params,
_vertex=vertex,
_tracing_service=get_tracing_service(),
+ _id=vertex.id,
)
if hasattr(custom_component, "set_event_manager"):
custom_component.set_event_manager(event_manager)
diff --git a/src/backend/base/langflow/memory.py b/src/backend/base/langflow/memory.py
index 86958c98a..61461fe24 100644
--- a/src/backend/base/langflow/memory.py
+++ b/src/backend/base/langflow/memory.py
@@ -1,12 +1,13 @@
+import json
from collections.abc import Sequence
from uuid import UUID
+from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.messages import BaseMessage
from loguru import logger
from sqlalchemy import delete
from sqlmodel import Session, col, select
-from langflow.field_typing import BaseChatMessageHistory
from langflow.schema.message import Message
from langflow.services.database.models.message.model import MessageRead, MessageTable
from langflow.services.deps import session_scope
@@ -74,6 +75,25 @@ def add_messages(messages: Message | list[Message], flow_id: str | None = None):
raise
+def update_messages(messages: Message | list[Message]) -> list[Message]:
+ if not isinstance(messages, list):
+ messages = [messages]
+
+ with session_scope() as session:
+ updated_messages: list[MessageTable] = []
+ for message in messages:
+ msg = session.get(MessageTable, message.id)
+ if msg:
+ msg.sqlmodel_update(message.model_dump(exclude_unset=True, exclude_none=True))
+ session.add(msg)
+ session.commit()
+ session.refresh(msg)
+ updated_messages.append(msg)
+ else:
+ logger.warning(f"Message with id {message.id} not found")
+ return [MessageRead.model_validate(message, from_attributes=True) for message in updated_messages]
+
+
def add_messagetables(messages: list[MessageTable], session: Session):
for message in messages:
try:
@@ -83,7 +103,15 @@ def add_messagetables(messages: list[MessageTable], session: Session):
except Exception as e:
logger.exception(e)
raise
- return [MessageRead.model_validate(message, from_attributes=True) for message in messages]
+
+ new_messages = []
+ for msg in messages:
+ msg.properties = json.loads(msg.properties) if isinstance(msg.properties, str) else msg.properties # type: ignore[arg-type]
+ msg.content_blocks = [json.loads(j) if isinstance(j, str) else j for j in msg.content_blocks] # type: ignore[arg-type]
+ msg.category = msg.category or ""
+ new_messages.append(msg)
+
+ return [MessageRead.model_validate(message, from_attributes=True) for message in new_messages]
def delete_messages(session_id: str) -> None:
@@ -100,6 +128,19 @@ def delete_messages(session_id: str) -> None:
)
+def delete_message(id_: str) -> None:
+ """Delete a message from the monitor service based on the provided ID.
+
+ Args:
+ id_ (str): The ID of the message to delete.
+ """
+ with session_scope() as session:
+ message = session.get(MessageTable, id_)
+ if message:
+ session.delete(message)
+ session.commit()
+
+
def store_message(
message: Message,
flow_id: str | None = None,
@@ -124,7 +165,8 @@ def store_message(
if not message.session_id or not message.sender or not message.sender_name:
msg = "All of session_id, sender, and sender_name must be provided."
raise ValueError(msg)
-
+ if hasattr(message, "id") and message.id:
+ return update_messages([message])
return add_messages([message], flow_id=flow_id)
diff --git a/src/backend/base/langflow/schema/content_block.py b/src/backend/base/langflow/schema/content_block.py
new file mode 100644
index 000000000..20e7c921e
--- /dev/null
+++ b/src/backend/base/langflow/schema/content_block.py
@@ -0,0 +1,34 @@
+from typing import Annotated
+
+from pydantic import BaseModel, Field
+from typing_extensions import TypedDict
+
+from .content_types import ContentTypes
+
+# Create a union type of all content types
+ContentType = Annotated[
+ ContentTypes,
+ Field(discriminator="type"),
+]
+
+
+class ContentBlock(BaseModel):
+ """A block of content that can contain different types of content."""
+
+ title: str
+ content: ContentType
+ allow_markdown: bool = Field(default=True)
+ media_url: list[str] | None = None
+
+ def __init__(self, **data) -> None:
+ super().__init__(**data)
+ fields = self.__pydantic_core_schema__["schema"]["fields"]
+ fields_with_default = (f for f, d in fields.items() if "default" in d["schema"])
+ self.model_fields_set.update(fields_with_default)
+
+
+class ContentBlockDict(TypedDict):
+ title: str
+ content: ContentType
+ allow_markdown: bool
+ media_url: list[str] | None
diff --git a/src/backend/base/langflow/schema/content_types.py b/src/backend/base/langflow/schema/content_types.py
new file mode 100644
index 000000000..9e9d3a88c
--- /dev/null
+++ b/src/backend/base/langflow/schema/content_types.py
@@ -0,0 +1,94 @@
+from typing import Any, Literal, TypeAlias
+
+from pydantic import BaseModel, Field
+
+
+class BaseContent(BaseModel):
+ """Base class for all content types."""
+
+ type: str = Field(..., description="Type of the content")
+
+ def to_dict(self) -> dict[str, Any]:
+ return self.model_dump()
+
+ @classmethod
+ def from_dict(cls, data: dict[str, Any]) -> "BaseContent":
+ return cls(**data)
+
+
+class ErrorContent(BaseContent):
+ """Content type for error messages."""
+
+ type: Literal["error"] = Field(default="error")
+ component: str | None = None
+ field: str | None = None
+ reason: str | None = None
+ solution: str | None = None
+ traceback: str | None = None
+
+
+class TextContent(BaseContent):
+ """Content type for simple text content."""
+
+ type: Literal["text"] = Field(default="text")
+ text: str
+
+
+class MediaContent(BaseContent):
+ """Content type for media content."""
+
+ type: Literal["media"] = Field(default="media")
+ urls: list[str]
+ caption: str | None = None
+
+
+class JSONContent(BaseContent):
+ """Content type for JSON content."""
+
+ type: Literal["json"] = Field(default="json")
+ data: dict[str, Any]
+
+
+class CodeContent(BaseContent):
+ """Content type for code snippets."""
+
+ type: Literal["code"] = Field(default="code")
+ code: str
+ language: str
+ title: str | None = None
+
+
+class ToolStartContent(BaseContent):
+ """Content type for tool start content."""
+
+ type: Literal["tool_start"] = Field(default="tool_start")
+ tool_name: str
+ tool_input: dict[str, Any]
+
+
+class ToolEndContent(BaseContent):
+ """Content type for tool end content."""
+
+ type: Literal["tool_end"] = Field(default="tool_end")
+ tool_name: str
+ tool_output: Any
+
+
+class ToolErrorContent(BaseContent):
+ """Content type for tool error content."""
+
+ type: Literal["tool_error"] = Field(default="tool_error")
+ tool_name: str
+ tool_error: str
+
+
+ContentTypes: TypeAlias = (
+ ToolStartContent
+ | ToolEndContent
+ | ToolErrorContent
+ | ErrorContent
+ | TextContent
+ | MediaContent
+ | CodeContent
+ | JSONContent
+)
diff --git a/src/backend/base/langflow/schema/data.py b/src/backend/base/langflow/schema/data.py
index 96971678c..e20e692eb 100644
--- a/src/backend/base/langflow/schema/data.py
+++ b/src/backend/base/langflow/schema/data.py
@@ -1,6 +1,9 @@
import copy
import json
+from datetime import datetime
+from decimal import Decimal
from typing import TYPE_CHECKING, cast
+from uuid import UUID
from langchain_core.documents import Document
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
@@ -8,7 +11,6 @@ from langchain_core.prompts.image import ImagePromptTemplate
from loguru import logger
from pydantic import BaseModel, model_serializer, model_validator
-from langflow.schema.serialize import recursive_serialize_or_str
from langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER
if TYPE_CHECKING:
@@ -200,8 +202,7 @@ class Data(BaseModel):
# return a JSON string representation of the Data atributes
try:
data = {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()}
- data = recursive_serialize_or_str(data)
- return json.dumps(data, indent=4)
+ return serialize_data(data) # use the custom serializer
except Exception: # noqa: BLE001
logger.opt(exception=True).debug("Error converting Data to JSON")
return str(self.data)
@@ -211,3 +212,21 @@ class Data(BaseModel):
def __eq__(self, other):
return isinstance(other, Data) and self.data == other.data
+
+
+def custom_serializer(obj):
+ if isinstance(obj, datetime):
+ return obj.astimezone().isoformat()
+ if isinstance(obj, Decimal):
+ return float(obj)
+ if isinstance(obj, UUID):
+ return str(obj)
+ if isinstance(obj, BaseModel):
+ return obj.model_dump()
+ # Add more custom serialization rules as needed
+ msg = f"Type {type(obj)} not serializable"
+ raise TypeError(msg)
+
+
+def serialize_data(data):
+ return json.dumps(data, indent=4, default=custom_serializer)
diff --git a/src/backend/base/langflow/schema/log.py b/src/backend/base/langflow/schema/log.py
index 72a6cb032..b3ddb338a 100644
--- a/src/backend/base/langflow/schema/log.py
+++ b/src/backend/base/langflow/schema/log.py
@@ -1,10 +1,29 @@
-from typing import TypeAlias
+from typing import Literal, TypeAlias
from pydantic import BaseModel
from typing_extensions import Protocol
-LoggableType: TypeAlias = str | dict | list | int | float | bool | None | BaseModel
+from langflow.schema.message import ContentBlock, Message
+from langflow.schema.playground_events import PlaygroundEvent
+
+LoggableType: TypeAlias = str | dict | list | int | float | bool | None | BaseModel | PlaygroundEvent
class LogFunctionType(Protocol):
def __call__(self, message: LoggableType | list[LoggableType], *, name: str | None = None) -> None: ...
+
+
+class SendMessageFunctionType(Protocol):
+ def __call__(
+ self,
+ message: Message | None = None,
+ text: str | None = None,
+ background_color: str | None = None,
+ text_color: str | None = None,
+ icon: str | None = None,
+ content_blocks: list[ContentBlock] | None = None,
+ format_type: Literal["default", "error", "warning", "info"] = "default",
+ id_: str | None = None,
+ *,
+ allow_markdown: bool = True,
+ ) -> None: ...
diff --git a/src/backend/base/langflow/schema/message.py b/src/backend/base/langflow/schema/message.py
index df7f634fb..a953fbf4c 100644
--- a/src/backend/base/langflow/schema/message.py
+++ b/src/backend/base/langflow/schema/message.py
@@ -1,9 +1,11 @@
from __future__ import annotations
import json
+import re
+import traceback
from collections.abc import AsyncIterator, Iterator
from datetime import datetime, timezone
-from typing import TYPE_CHECKING, Annotated, Any
+from typing import TYPE_CHECKING, Annotated, Any, Literal
from uuid import UUID
from fastapi.encoders import jsonable_encoder
@@ -12,11 +14,15 @@ from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, System
from langchain_core.prompts import BaseChatPromptTemplate, ChatPromptTemplate, PromptTemplate
from langchain_core.prompts.image import ImagePromptTemplate
from loguru import logger
-from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, field_serializer, field_validator
+from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator
from langflow.base.prompts.utils import dict_values_to_string
+from langflow.schema.content_block import ContentBlock
+from langflow.schema.content_types import ErrorContent
from langflow.schema.data import Data
from langflow.schema.image import Image, get_file_paths, is_image_file
+from langflow.schema.properties import Properties, Source
+from langflow.schema.utils import timestamp_to_str_validator # noqa: TCH001
from langflow.utils.constants import (
MESSAGE_SENDER_AI,
MESSAGE_SENDER_NAME_AI,
@@ -28,18 +34,6 @@ if TYPE_CHECKING:
from langchain_core.prompt_values import ImagePromptValue
-def _timestamp_to_str(timestamp: datetime | str) -> str:
- if isinstance(timestamp, str):
- # Just check if the string is a valid datetime
- try:
- datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S") # noqa: DTZ007
- except ValueError as e:
- msg = f"Invalid timestamp: {timestamp}"
- raise ValueError(msg) from e
- return timestamp
- return timestamp.strftime("%Y-%m-%d %H:%M:%S")
-
-
class Message(Data):
model_config = ConfigDict(arbitrary_types_allowed=True)
# Helper class to deal with image data
@@ -49,13 +43,17 @@ class Message(Data):
sender_name: str | None = None
files: list[str | Image] | None = Field(default=[])
session_id: str | None = Field(default="")
- timestamp: Annotated[str, BeforeValidator(_timestamp_to_str)] = Field(
- default_factory=lambda: datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
+ timestamp: Annotated[str, timestamp_to_str_validator] = Field(
+ default_factory=lambda: datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S %Z")
)
flow_id: str | UUID | None = None
error: bool = Field(default=False)
edit: bool = Field(default=False)
+ properties: Properties = Field(default_factory=Properties)
+ category: Literal["message", "error", "warning", "info"] | None = "message"
+ content_blocks: list[ContentBlock] = Field(default_factory=list)
+
@field_validator("flow_id", mode="before")
@classmethod
def validate_flow_id(cls, value):
@@ -71,7 +69,12 @@ class Message(Data):
@field_serializer("timestamp")
def serialize_timestamp(self, value):
- return datetime.strptime(value, "%Y-%m-%d %H:%M:%S").astimezone(timezone.utc)
+ try:
+ # Try parsing with timezone
+ return datetime.strptime(value.strip(), "%Y-%m-%d %H:%M:%S %Z").astimezone(timezone.utc)
+ except ValueError:
+ # Try parsing without timezone
+ return datetime.strptime(value.strip(), "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
@field_validator("files", mode="before")
@classmethod
@@ -270,6 +273,11 @@ class MessageResponse(DefaultModel):
session_id: str
text: str
files: list[str] = []
+ edit: bool
+
+ properties: Properties | None = None
+ category: str | None = None
+ content_blocks: list[ContentBlock] | None = None
@field_validator("files", mode="before")
@classmethod
@@ -282,7 +290,7 @@ class MessageResponse(DefaultModel):
@classmethod
def serialize_timestamp(cls, v):
v = v.replace(microsecond=0)
- return v.strftime("%Y-%m-%d %H:%M:%S")
+ return v.strftime("%Y-%m-%d %H:%M:%S %Z")
@field_serializer("files")
@classmethod
@@ -306,3 +314,60 @@ class MessageResponse(DefaultModel):
timestamp=message.timestamp,
flow_id=flow_id,
)
+
+
+class ErrorMessage(Message):
+ """A message class specifically for error messages with predefined error-specific attributes."""
+
+ def __init__(
+ self,
+ exception: Exception,
+ session_id: str,
+ source: Source,
+ trace_name: str | None = None,
+ flow_id: str | None = None,
+ ) -> None:
+ # Get the error reason
+ reason = exception.__class__.__name__
+ if hasattr(exception, "body") and "message" in exception.body:
+ reason = exception.body.get("message")
+ elif hasattr(exception, "code"):
+ reason = exception.code
+
+ # Get the sender ID
+ if trace_name:
+ match = re.search(r"\((.*?)\)", trace_name)
+ if match:
+ match.group(1)
+
+ super().__init__(
+ session_id=session_id,
+ sender=source.display_name,
+ sender_name=source.display_name,
+ text=reason,
+ properties=Properties(
+ text_color="red",
+ background_color="red",
+ edited=False,
+ source=source,
+ icon="error",
+ allow_markdown=False,
+ targets=[],
+ ),
+ category="error",
+ error=True,
+ content_blocks=[
+ ContentBlock(
+ title="Error",
+ content=ErrorContent(
+ type="error",
+ component=source.display_name,
+ field=str(exception.field) if hasattr(exception, "field") else None,
+ reason=reason,
+ solution=str(exception.solution) if hasattr(exception, "solution") else None,
+ traceback=traceback.format_exc(),
+ ),
+ )
+ ],
+ flow_id=flow_id,
+ )
diff --git a/src/backend/base/langflow/schema/playground_events.py b/src/backend/base/langflow/schema/playground_events.py
new file mode 100644
index 000000000..d66bd39de
--- /dev/null
+++ b/src/backend/base/langflow/schema/playground_events.py
@@ -0,0 +1,180 @@
+import inspect
+from collections.abc import Callable
+from datetime import datetime, timezone
+from typing import Annotated, Literal
+from uuid import UUID
+
+from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator
+
+from langflow.schema.content_block import ContentBlock
+from langflow.schema.properties import Properties
+from langflow.schema.utils import timestamp_to_str_validator
+from langflow.utils.constants import MESSAGE_SENDER_USER
+
+
+class PlaygroundEvent(BaseModel):
+ model_config = ConfigDict(extra="allow", populate_by_name=True)
+ properties: Properties | None = Field(default=None)
+ sender_name: str | None = Field(default=None)
+ content_blocks: list[ContentBlock] | None = Field(default=None)
+ format_type: Literal["default", "error", "warning", "info"] = Field(default="default")
+ files: list[str] | None = Field(default=None)
+ text: str | None = Field(default=None)
+ timestamp: Annotated[str, timestamp_to_str_validator] = Field(
+ default_factory=lambda: datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S %Z")
+ )
+ id_: UUID | str | None = Field(alias="id")
+
+ @field_serializer("timestamp")
+ @classmethod
+ def serialize_timestamp(cls, v: str) -> str:
+ return v
+
+ @field_validator("id_")
+ @classmethod
+ def validate_id(cls, v: UUID | str | None) -> str | None:
+ if isinstance(v, UUID):
+ return str(v)
+ return v
+
+
+class MessageEvent(PlaygroundEvent):
+ category: Literal["message", "error", "warning", "info"] = "message"
+ format_type: Literal["default", "error", "warning", "info"] = Field(default="default")
+ session_id: str | None = Field(default=None)
+ error: bool = Field(default=False)
+ edit: bool = Field(default=False)
+ flow_id: UUID | str | None = Field(default=None)
+ sender: str = Field(default=MESSAGE_SENDER_USER)
+ sender_name: str = Field(default="User")
+
+ @field_validator("flow_id")
+ @classmethod
+ def validate_flow_id(cls, v: UUID | str | None) -> str | None:
+ if isinstance(v, UUID):
+ return str(v)
+ return v
+
+
+class ErrorEvent(MessageEvent):
+ background_color: str = Field(default="#FF0000")
+ text_color: str = Field(default="#FFFFFF")
+ format_type: Literal["default", "error", "warning", "info"] = Field(default="error")
+ allow_markdown: bool = Field(default=False)
+ category: Literal["error"] = "error"
+
+
+class WarningEvent(PlaygroundEvent):
+ background_color: str = Field(default="#FFA500")
+ text_color: str = Field(default="#000000")
+ format_type: Literal["default", "error", "warning", "info"] = Field(default="warning")
+
+
+class InfoEvent(PlaygroundEvent):
+ background_color: str = Field(default="#0000FF")
+ text_color: str = Field(default="#FFFFFF")
+ format_type: Literal["default", "error", "warning", "info"] = Field(default="info")
+
+
+class TokenEvent(BaseModel):
+ chunk: str = Field(...)
+ id: UUID | str | None = Field(alias="id")
+ timestamp: Annotated[str, timestamp_to_str_validator] = Field(
+ default_factory=lambda: datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S %Z")
+ )
+
+
+# Factory functions first
+def create_message(
+ text: str,
+ category: Literal["message", "error", "warning", "info"] = "message",
+ properties: dict | None = None,
+ content_blocks: list[ContentBlock] | None = None,
+ sender_name: str | None = None,
+ files: list[str] | None = None,
+ timestamp: str | None = None,
+ format_type: Literal["default", "error", "warning", "info"] = "default",
+ sender: str | None = None,
+ session_id: str | None = None,
+ id: UUID | str | None = None, # noqa: A002
+ flow_id: UUID | str | None = None,
+ *,
+ error: bool = False,
+ edit: bool = False,
+) -> MessageEvent:
+ return MessageEvent(
+ text=text,
+ properties=properties,
+ category=category,
+ content_blocks=content_blocks,
+ sender_name=sender_name,
+ files=files,
+ timestamp=timestamp,
+ format_type=format_type,
+ sender=sender,
+ id=id,
+ session_id=session_id,
+ error=error,
+ edit=edit,
+ flow_id=flow_id,
+ )
+
+
+def create_error(
+ text: str,
+ properties: dict | None = None,
+ traceback: str | None = None,
+ title: str = "Error",
+ timestamp: str | None = None,
+ id: UUID | str | None = None, # noqa: A002
+ flow_id: UUID | str | None = None,
+ session_id: str | None = None,
+ content_blocks: list[ContentBlock] | None = None,
+) -> ErrorEvent:
+ if traceback:
+ content_blocks = content_blocks or []
+ content_blocks += [ContentBlock(title=title, content=traceback)]
+ return ErrorEvent(
+ text=text,
+ properties=properties,
+ content_blocks=content_blocks,
+ timestamp=timestamp,
+ id=id,
+ flow_id=flow_id,
+ session_id=session_id,
+ )
+
+
+def create_warning(message: str) -> WarningEvent:
+ return WarningEvent(text=message)
+
+
+def create_info(message: str) -> InfoEvent:
+ return InfoEvent(text=message)
+
+
+def create_token(chunk: str, id: str) -> TokenEvent: # noqa: A002
+ return TokenEvent(
+ chunk=chunk,
+ id=id,
+ )
+
+
+_EVENT_CREATORS: dict[str, tuple[Callable, inspect.Signature]] = {
+ "message": (create_message, inspect.signature(create_message)),
+ "error": (create_error, inspect.signature(create_error)),
+ "warning": (create_warning, inspect.signature(create_warning)),
+ "info": (create_info, inspect.signature(create_info)),
+ "token": (create_token, inspect.signature(create_token)),
+}
+
+
+def create_event_by_type(
+ event_type: Literal["message", "error", "warning", "info", "token"], **kwargs
+) -> PlaygroundEvent | dict:
+ if event_type not in _EVENT_CREATORS:
+ return kwargs
+
+ creator_func, signature = _EVENT_CREATORS[event_type]
+ valid_params = {k: v for k, v in kwargs.items() if k in signature.parameters}
+ return creator_func(**valid_params)
diff --git a/src/backend/base/langflow/schema/properties.py b/src/backend/base/langflow/schema/properties.py
new file mode 100644
index 000000000..ecb7bfe0a
--- /dev/null
+++ b/src/backend/base/langflow/schema/properties.py
@@ -0,0 +1,27 @@
+from pydantic import BaseModel, Field, field_validator
+
+
+class Source(BaseModel):
+ id: str = Field(default="", description="The id of the source component.")
+ display_name: str = Field(default="", description="The display name of the source component.")
+ source: str = Field(
+ default="",
+ description="The source of the message. Normally used to display the model name (e.g. 'gpt-4o')",
+ )
+
+
+class Properties(BaseModel):
+ text_color: str | None = None
+ background_color: str | None = None
+ edited: bool = False
+ source: Source = Field(default_factory=Source)
+ icon: str | None = None
+ allow_markdown: bool = False
+ targets: list = []
+
+ @field_validator("source", mode="before")
+ @classmethod
+ def validate_source(cls, v):
+ if isinstance(v, str):
+ return Source(id=v, display_name=v, source=v)
+ return v
diff --git a/src/backend/base/langflow/schema/utils.py b/src/backend/base/langflow/schema/utils.py
new file mode 100644
index 000000000..ecaaa4f7f
--- /dev/null
+++ b/src/backend/base/langflow/schema/utils.py
@@ -0,0 +1,20 @@
+from datetime import datetime
+
+from pydantic import BeforeValidator
+
+
+def timestamp_to_str(timestamp: datetime | str) -> str:
+ if isinstance(timestamp, str):
+ # Just check if the string is a valid datetime
+ try:
+ datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S %Z") # noqa: DTZ007
+ result = timestamp
+ except ValueError as e:
+ msg = f"Invalid timestamp: {timestamp}"
+ raise ValueError(msg) from e
+ else:
+ result = timestamp.strftime("%Y-%m-%d %H:%M:%S %Z")
+ return result
+
+
+timestamp_to_str_validator = BeforeValidator(timestamp_to_str)
diff --git a/src/backend/base/langflow/services/database/models/message/model.py b/src/backend/base/langflow/services/database/models/message/model.py
index 89d26bab6..45391fe02 100644
--- a/src/backend/base/langflow/services/database/models/message/model.py
+++ b/src/backend/base/langflow/services/database/models/message/model.py
@@ -2,10 +2,13 @@ from datetime import datetime, timezone
from typing import TYPE_CHECKING
from uuid import UUID, uuid4
-from pydantic import field_validator
+from pydantic import field_serializer, field_validator
from sqlalchemy import Text
from sqlmodel import JSON, Column, Field, Relationship, SQLModel
+from langflow.schema.content_block import ContentBlock, ContentBlockDict
+from langflow.schema.properties import Properties
+
if TYPE_CHECKING:
from langflow.schema.message import Message
from langflow.services.database.models.flow.model import Flow
@@ -21,6 +24,10 @@ class MessageBase(SQLModel):
error: bool = Field(default=False)
edit: bool = Field(default=False)
+ properties: Properties = Field(default_factory=Properties)
+ category: str = Field(default="message")
+ content_blocks: list[ContentBlock] = Field(default_factory=list)
+
@field_validator("files", mode="before")
@classmethod
def validate_files(cls, value):
@@ -44,10 +51,12 @@ class MessageBase(SQLModel):
message.files = image_paths
if isinstance(message.timestamp, str):
- # The message.timestamp is created using strftime("%Y-%m-%dT%H:%M:%S").
- # This format is not fully ISO 8601 compliant because it lacks timezone information.
- # Aadd timezone info (UTC) back to the timestamp here.
- timestamp = datetime.fromisoformat(message.timestamp).replace(tzinfo=timezone.utc)
+ # Convert timestamp string in format "YYYY-MM-DD HH:MM:SS UTC" to datetime
+ try:
+ timestamp = datetime.strptime(message.timestamp, "%Y-%m-%d %H:%M:%S %Z").replace(tzinfo=timezone.utc)
+ except ValueError:
+ # Fallback for ISO format if the above fails
+ timestamp = datetime.fromisoformat(message.timestamp).replace(tzinfo=timezone.utc)
else:
timestamp = message.timestamp
if not flow_id and message.flow_id:
@@ -55,6 +64,17 @@ class MessageBase(SQLModel):
# If the text is not a string, it means it could be
# async iterator so we simply add it as an empty string
message_text = "" if not isinstance(message.text, str) else message.text
+
+ properties = (
+ message.properties.model_dump_json()
+ if hasattr(message.properties, "model_dump_json")
+ else message.properties
+ )
+ content_blocks = []
+ for content_block in message.content_blocks or []:
+ content = content_block.model_dump_json() if hasattr(content_block, "model_dump_json") else content_block
+ content_blocks.append(content)
+
return cls(
sender=message.sender,
sender_name=message.sender_name,
@@ -63,6 +83,9 @@ class MessageBase(SQLModel):
files=message.files or [],
timestamp=timestamp,
flow_id=flow_id,
+ properties=properties,
+ category=message.category,
+ content_blocks=content_blocks,
)
@@ -72,6 +95,9 @@ class MessageTable(MessageBase, table=True): # type: ignore[call-arg]
flow_id: UUID | None = Field(default=None, foreign_key="flow.id")
flow: "Flow" = Relationship(back_populates="messages")
files: list[str] = Field(sa_column=Column(JSON))
+ properties: Properties = Field(default_factory=lambda: Properties().model_dump(), sa_column=Column(JSON)) # type: ignore[assignment]
+ category: str = Field(sa_column=Column(Text))
+ content_blocks: list[ContentBlockDict] = Field(default_factory=list, sa_column=Column(JSON)) # type: ignore[assignment]
@field_validator("flow_id", mode="before")
@classmethod
@@ -82,6 +108,20 @@ class MessageTable(MessageBase, table=True): # type: ignore[call-arg]
value = UUID(value)
return value
+ @field_validator("properties")
+ @classmethod
+ def validate_properties(cls, value):
+ if hasattr(value, "model_dump"):
+ return value.model_dump()
+ return value
+
+ @field_serializer("properties")
+ @classmethod
+ def serialize_properties(cls, value):
+ if hasattr(value, "model_dump"):
+ return value.model_dump()
+ return value
+
# Needed for Column(JSON)
class Config:
arbitrary_types_allowed = True
diff --git a/src/backend/tests/integration/components/outputs/test_chat_output.py b/src/backend/tests/integration/components/outputs/test_chat_output.py
index 24fd047e2..dfe113cc9 100644
--- a/src/backend/tests/integration/components/outputs/test_chat_output.py
+++ b/src/backend/tests/integration/components/outputs/test_chat_output.py
@@ -24,7 +24,7 @@ async def test_message():
async def test_do_not_store_message():
session_id = "test-session-id"
outputs = await run_single_component(
- ChatOutput, inputs={"input_value": "hello", "should_store_message": True}, session_id=session_id
+ ChatOutput, inputs={"input_value": Message(text="hello"), "should_store_message": True}, session_id=session_id
)
assert isinstance(outputs["message"], Message)
assert outputs["message"].text == "hello"
@@ -33,7 +33,7 @@ async def test_do_not_store_message():
session_id = "test-session-id-another"
outputs = await run_single_component(
- ChatOutput, inputs={"input_value": "hello", "should_store_message": False}, session_id=session_id
+ ChatOutput, inputs={"input_value": Message(text="hello"), "should_store_message": False}, session_id=session_id
)
assert isinstance(outputs["message"], Message)
assert outputs["message"].text == "hello"
diff --git a/src/backend/tests/unit/base/tools/test_component_toolkit.py b/src/backend/tests/unit/base/tools/test_component_toolkit.py
index cdde22577..f5424d3e5 100644
--- a/src/backend/tests/unit/base/tools/test_component_toolkit.py
+++ b/src/backend/tests/unit/base/tools/test_component_toolkit.py
@@ -72,6 +72,24 @@ def test_component_tool():
"title": "Files",
"type": "array",
},
+ "background_color": {
+ "default": "",
+ "description": "The background color of the icon.",
+ "title": "Background Color",
+ "type": "string",
+ },
+ "chat_icon": {
+ "default": "",
+ "description": "The icon of the message.",
+ "title": "Chat Icon",
+ "type": "string",
+ },
+ "text_color": {
+ "default": "",
+ "description": "The text color of the name",
+ "title": "Text Color",
+ "type": "string",
+ },
}
assert component_toolkit.component == chat_input
diff --git a/src/backend/tests/unit/events/test_event_manager.py b/src/backend/tests/unit/events/test_event_manager.py
index 1a7a0d84f..4b15518d1 100644
--- a/src/backend/tests/unit/events/test_event_manager.py
+++ b/src/backend/tests/unit/events/test_event_manager.py
@@ -198,7 +198,16 @@ class TestEventManager:
assert len(queue.data) == 1
event_id, str_data, timestamp = queue.data[0]
- assert isinstance(event_id, uuid.UUID)
+ # event_id follows this pattern: f"{event_type}-{uuid.uuid4()}"
+ event_type_from_id = event_id.split("-")[0]
+ assert event_type_from_id == "test_type"
+ uuid_from_id = event_id.split(event_type_from_id)[1]
+ assert isinstance(uuid_from_id, str)
+ # assert that the uuid_from_id is a valid uuid
+ try:
+ uuid.UUID(uuid_from_id)
+ except ValueError:
+ pytest.fail(f"Invalid UUID: {uuid_from_id}")
assert isinstance(str_data, bytes)
assert isinstance(timestamp, float)
diff --git a/src/backend/tests/unit/graph/graph/test_callback_graph.py b/src/backend/tests/unit/graph/graph/test_callback_graph.py
index 30fd86e18..f497924e9 100644
--- a/src/backend/tests/unit/graph/graph/test_callback_graph.py
+++ b/src/backend/tests/unit/graph/graph/test_callback_graph.py
@@ -10,7 +10,7 @@ from langflow.template import Output
class LogComponent(Component):
- name = "LogComponent"
+ display_name = "LogComponent"
inputs = [IntInput(name="times", value=1)]
outputs = [Output(name="call_log", method="call_log_method")]
diff --git a/src/frontend/src/assets/logo.svg b/src/frontend/src/assets/logo.svg
new file mode 100644
index 000000000..24c721e4a
--- /dev/null
+++ b/src/frontend/src/assets/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/frontend/src/components/cardComponent/index.tsx b/src/frontend/src/components/cardComponent/index.tsx
index d5d2ab645..a92aa1e23 100644
--- a/src/frontend/src/components/cardComponent/index.tsx
+++ b/src/frontend/src/components/cardComponent/index.tsx
@@ -40,7 +40,7 @@ export default function CollectionCardComponent({
const setErrorData = useAlertStore((state) => state.setErrorData);
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
const getFlowById = useFlowsManagerStore((state) => state.getFlowById);
- const [openPlayground, setOpenPlayground] = useState(false);
+ // const [openPlayground, setOpenPlayground] = useState(false);
const [loadingPlayground, setLoadingPlayground] = useState(false);
const selectedFlowsComponentsCards = useFlowsManagerStore(
(state) => state.selectedFlowsComponentsCards,
@@ -75,7 +75,7 @@ export default function CollectionCardComponent({
return;
}
setCurrentFlow(data);
- setOpenPlayground(true);
+ // setOpenPlayground(true);
setLoadingPlayground(false);
} else {
setErrorData({
@@ -156,7 +156,7 @@ export default function CollectionCardComponent({