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({
- {playground && ( + {/* {playground && (
- {openPlayground && ( + {/* {openPlayground && ( <> - )} + )} */} ); } diff --git a/src/frontend/src/components/cardsWrapComponent/index.tsx b/src/frontend/src/components/cardsWrapComponent/index.tsx index c7ca01588..3dec7c8e2 100644 --- a/src/frontend/src/components/cardsWrapComponent/index.tsx +++ b/src/frontend/src/components/cardsWrapComponent/index.tsx @@ -1,3 +1,4 @@ +import useFlowsManagerStore from "@/stores/flowsManagerStore"; import { useEffect, useState } from "react"; import IconComponent from "../../components/genericIconComponent"; import { cn } from "../../utils/utils"; @@ -12,6 +13,7 @@ export default function CardsWrapComponent({ dragMessage?: string; }) { const [isDragging, setIsDragging] = useState(false); + const isIOModalOpen = useFlowsManagerStore((state) => state.IOModalOpen); useEffect(() => { // Function to handle visibility change const handleVisibilityChange = () => { @@ -32,13 +34,21 @@ export default function CardsWrapComponent({ const dragOver = (e) => { e.preventDefault(); - if (e.dataTransfer.types.some((types) => types === "Files") && onFileDrop) { + if ( + e.dataTransfer.types.some((types) => types === "Files") && + onFileDrop && + !isIOModalOpen + ) { setIsDragging(true); } }; const dragEnter = (e) => { - if (e.dataTransfer.types.some((types) => types === "Files") && onFileDrop) { + if ( + e.dataTransfer.types.some((types) => types === "Files") && + onFileDrop && + !isIOModalOpen + ) { setIsDragging(true); } e.preventDefault(); @@ -46,12 +56,12 @@ export default function CardsWrapComponent({ const dragLeave = (e) => { e.preventDefault(); - if (onFileDrop) setIsDragging(false); + if (onFileDrop && !isIOModalOpen) setIsDragging(false); }; const onDrop = (e) => { e.preventDefault(); - if (onFileDrop) onFileDrop(e); + if (onFileDrop && !isIOModalOpen) onFileDrop(e); setIsDragging(false); }; diff --git a/src/frontend/src/components/codeTabsComponent/ChatCodeTabComponent.tsx b/src/frontend/src/components/codeTabsComponent/ChatCodeTabComponent.tsx index a1809314e..4ac235540 100644 --- a/src/frontend/src/components/codeTabsComponent/ChatCodeTabComponent.tsx +++ b/src/frontend/src/components/codeTabsComponent/ChatCodeTabComponent.tsx @@ -31,13 +31,14 @@ export default function SimplifiedCodeTabComponent({ }; return ( -
-
- {language} +
+
+ {language} -
+ +
+ + +
+
); }; diff --git a/src/frontend/src/modals/IOModal/components/chatView/chatInput/newChatInput.tsx b/src/frontend/src/modals/IOModal/components/chatView/chatInput/newChatInput.tsx index ea5c54e3c..c1902b50f 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/chatInput/newChatInput.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/chatInput/newChatInput.tsx @@ -1,7 +1,9 @@ import { Button } from "@/components/ui/button"; +import Loading from "@/components/ui/loading"; import { usePostUploadFile } from "@/controllers/API/queries/files/use-post-upload-file"; import useFileSizeValidator from "@/shared/hooks/use-file-size-validator"; import useAlertStore from "@/stores/alertStore"; +import useFlowStore from "@/stores/flowStore"; import { useEffect, useRef, useState } from "react"; import ShortUniqueId from "short-unique-id"; import { @@ -38,6 +40,7 @@ export default function ChatInput({ const fileInputRef = useRef(null); const setErrorData = useAlertStore((state) => state.setErrorData); const { validateFileSize } = useFileSizeValidator(setErrorData); + const stopBuilding = useFlowStore((state) => state.stopBuilding); useFocusOnUnlock(lockChat, inputRef); useAutoResizeTextArea(chatValue, inputRef); @@ -150,7 +153,7 @@ export default function ChatInput({ ); }; - const classNameFilePreview = `flex w-full items-center gap-2 bg-background py-2 overflow-auto custom-scroll`; + const classNameFilePreview = `flex w-full items-center gap-2 py-2 overflow-auto custom-scroll`; const handleButtonClick = () => { fileInputRef.current!.click(); @@ -164,17 +167,33 @@ export default function ChatInput({ if (noInput) { return (
-
- +
+ {!lockChat ? ( + + ) : ( + + )} +

Add a{" "} -

+
+
+ Chain logo +
+
+ ); +} diff --git a/src/frontend/src/modals/IOModal/components/chatView/chatMessage/components/editMessageButton/newMessageOptions.tsx b/src/frontend/src/modals/IOModal/components/chatView/chatMessage/components/editMessageButton/newMessageOptions.tsx index f878f0091..dc87c362e 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/chatMessage/components/editMessageButton/newMessageOptions.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/chatMessage/components/editMessageButton/newMessageOptions.tsx @@ -31,14 +31,14 @@ export function EditMessageButton({ return (
-
+
@@ -48,12 +48,12 @@ export function EditMessageButton({ content={isCopied ? "Copied!" : "Copy message"} side="top" > -
+