fix: reorder playground messages, fix scroll behavior (#7928)

* updated vite-env to stop svg loading lint errors

* added scroll direction package

* added new Chat Scroll Anchor

* removed scroll handling from chat message

* added scroll handling on chat view

* removed console.log

* Removed validator from table and added on messagebase

* removed validator from model

* changed to scroll down after error

* [autofix.ci] apply automated fixes

* fixed not scrolling to bottom

* fix constant

* refactor: update MessageTable model configuration for validation and type allowance

* refactor: update properties type in MessageTable model and adjust validation logic

* refactor: update content_blocks type in MessageTable model to allow dict or ContentBlock

* Fix playground failing when it's Run Flow

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Carlos Coelho <80289056+carlosrcoelho@users.noreply.github.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
This commit is contained in:
Lucas Oliveira 2025-05-08 16:41:54 -03:00 • committed by GitHub
commit be1caf2b61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 139 additions and 65 deletions

View file

@ -1311,7 +1311,7 @@ class Component(CustomComponent):
async def _send_message_event(self, message: Message, id_: str | None = None, category: str | None = None) -> None:
if hasattr(self, "_event_manager") and self._event_manager:
data_dict = message.data.copy() if hasattr(message, "data") else message.model_dump()
data_dict = message.model_dump()["data"] if hasattr(message, "data") else message.model_dump()
if id_ and not data_dict.get("id"):
data_dict["id"] = id_
category = category or data_dict.get("category", None)

View file

@ -3,6 +3,7 @@ from datetime import datetime, timezone
from typing import TYPE_CHECKING, Annotated
from uuid import UUID, uuid4
from litellm import ConfigDict
from pydantic import field_serializer, field_validator
from sqlalchemy import Text
from sqlmodel import JSON, Column, Field, SQLModel
@ -31,11 +32,16 @@ class MessageBase(SQLModel):
category: str = Field(default="message")
content_blocks: list[ContentBlock] = Field(default_factory=list)
@field_validator("timestamp", mode="before")
@classmethod
def validate_timestamp(cls, value):
@field_serializer("timestamp")
def serialize_timestamp(self, value):
if isinstance(value, datetime):
if value.tzinfo is None:
value = value.replace(tzinfo=timezone.utc)
return value.strftime("%Y-%m-%d %H:%M:%S %Z")
if isinstance(value, str):
return datetime.fromisoformat(value)
# Make sure the timestamp is in UTC
value = datetime.fromisoformat(value).replace(tzinfo=timezone.utc)
return value.strftime("%Y-%m-%d %H:%M:%S %Z")
return value
@field_validator("files", mode="before")
@ -110,36 +116,20 @@ class MessageBase(SQLModel):
class MessageTable(MessageBase, table=True): # type: ignore[call-arg]
model_config = ConfigDict(validate_assignment=True, arbitrary_types_allowed=True)
__tablename__ = "message"
id: UUID = Field(default_factory=uuid4, primary_key=True)
flow_id: UUID | None = Field(default=None)
files: list[str] = Field(sa_column=Column(JSON))
properties: Properties = Field(default_factory=lambda: Properties().model_dump(), sa_column=Column(JSON)) # type: ignore[assignment]
properties: dict | 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[ContentBlock] = Field(default_factory=list, sa_column=Column(JSON)) # type: ignore[assignment]
content_blocks: list[dict | ContentBlock] = Field(default_factory=list, sa_column=Column(JSON)) # type: ignore[assignment]
# We need to make sure the datetimes have timezone after running session.refresh
# because we are losing the timezone information when we save the message to the database
# and when we read it back. We use field_validator to make sure the datetimes have timezone
# after running session.refresh
@field_validator("timestamp", mode="after")
@classmethod
def validate_timestamp(cls, value):
if isinstance(value, datetime):
return value.replace(tzinfo=timezone.utc)
return value
@field_serializer("timestamp")
def serialize_timestamp(self, value, _info):
if isinstance(value, datetime):
if value.tzinfo is None:
value = value.replace(tzinfo=timezone.utc)
return value.strftime("%Y-%m-%d %H:%M:%S %Z")
if isinstance(value, str):
# Make sure the timestamp is in UTC
value = datetime.fromisoformat(value).replace(tzinfo=timezone.utc)
return value.strftime("%Y-%m-%d %H:%M:%S %Z")
return value
@field_validator("flow_id", mode="before")
@classmethod
@ -150,7 +140,7 @@ class MessageTable(MessageBase, table=True): # type: ignore[call-arg]
value = UUID(value)
return value
@field_validator("properties", "content_blocks")
@field_validator("properties", "content_blocks", mode="before")
@classmethod
def validate_properties_or_content_blocks(cls, value):
if isinstance(value, list):
@ -162,19 +152,16 @@ class MessageTable(MessageBase, table=True): # type: ignore[call-arg]
return value
@field_serializer("properties", "content_blocks")
def serialize_properties_or_content_blocks(self, value) -> dict | list[dict]:
@classmethod
def serialize_properties_or_content_blocks(cls, value) -> dict | list[dict]:
if isinstance(value, list):
return [self.serialize_properties_or_content_blocks(item) for item in value]
return [cls.serialize_properties_or_content_blocks(item) for item in value]
if hasattr(value, "model_dump"):
return value.model_dump()
if isinstance(value, str):
return json.loads(value)
return value
# Needed for Column(JSON)
class Config:
arbitrary_types_allowed = True
class MessageRead(MessageBase):
id: UUID