Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
0eab437
Fix agents; only stream the current chunk back
jordanrfrazier Sep 24, 2025
bb65ba9
Fix length access
jordanrfrazier Sep 24, 2025
3992e04
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 24, 2025
755bd78
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Sep 24, 2025
53cd69d
move the empty text skips to the agent
jordanrfrazier Sep 24, 2025
e380871
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 24, 2025
9e621de
Fix message type - passes token now
jordanrfrazier Sep 24, 2025
aafbdf0
rebase fixes
jordanrfrazier Oct 10, 2025
3e84c65
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 10, 2025
56dcb12
Fix tests for new beahvior with eventmgr
jordanrfrazier Oct 10, 2025
2acf2fc
Update vector store rag starter project
erichare Oct 10, 2025
f2c2171
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 10, 2025
5de3091
Ruff fixes
jordanrfrazier Oct 10, 2025
2e1c798
Add back params
jordanrfrazier Oct 10, 2025
1d17d69
Add event manager
jordanrfrazier Oct 11, 2025
65b3ed4
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 11, 2025
decf529
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Oct 11, 2025
e8bfb76
combine if sttements
jordanrfrazier Oct 11, 2025
7b3ea57
Cleanup passing of callbacks
jordanrfrazier Oct 13, 2025
99268a7
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 13, 2025
abed50d
remove added content param on component
jordanrfrazier Oct 13, 2025
f6182c7
Update how empty data is passed to fastapi endpoint -- removes embed=…
jordanrfrazier Oct 13, 2025
00adb50
Revert "Update how empty data is passed to fastapi endpoint -- remove…
jordanrfrazier Oct 13, 2025
f8100de
Add uv lock from 1.6.4 to not upgrade deps
jordanrfrazier Oct 13, 2025
361732a
Ruff, tests, mypy
jordanrfrazier Oct 13, 2025
991e936
Ruff, tests, mypy
jordanrfrazier Oct 13, 2025
9c0df28
Fix tests to use token callback instead of event manager
jordanrfrazier Oct 13, 2025
ea9b33d
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 13, 2025
70de4ca
rebase redundant fixes
jordanrfrazier Oct 13, 2025
0ce2576
uv lock
jordanrfrazier Oct 13, 2025
9d53282
simplify the run agent method
jordanrfrazier Oct 13, 2025
007c220
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 13, 2025
b3ebf72
Ensure the input is the text content
jordanrfrazier Oct 13, 2025
d47be51
Use actual text instead of lc_message content
jordanrfrazier Oct 13, 2025
1042480
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 13, 2025
e1d65f3
keep message id consistent throughout streaming
jordanrfrazier Oct 14, 2025
afddccd
remove comment that lint didn't like
jordanrfrazier Oct 14, 2025
2ea0290
ruff
jordanrfrazier Oct 14, 2025
15ade5f
Merge branch 'release-1.6.5' into fix-agent-streaming-tokens
jordanrfrazier Oct 14, 2025
f289de7
Be a little more lenient in sorting tests
jordanrfrazier Oct 14, 2025
86d0931
Fix test to not call persistence layer
jordanrfrazier Oct 14, 2025
ca54754
Add multimodal test
jordanrfrazier Oct 14, 2025
f54c461
mypy
jordanrfrazier Oct 14, 2025
8f43960
lint
jordanrfrazier Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
move the empty text skips to the agent
  • Loading branch information
jordanrfrazier committed Oct 13, 2025
commit 53cd69de16c55259d5cb2186e9b6603cefd2f30b
27 changes: 23 additions & 4 deletions src/backend/base/langflow/base/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,24 @@ def get_chat_history_data(self) -> list[Data] | None:
# might be overridden in subclasses
return None

def _data_to_messages_skip_empty(self, data: list[Data]):
"""Convert data to messages, filtering only empty text while preserving non-text content.

Note: added to fix issue with certain providers failing when given empty text.
"""
messages = []
for value in data:
# Only skip if the message has a text attribute that is empty/whitespace
text = getattr(value, "text", None)
if isinstance(text, str) and not text.strip():
# Skip only messages with empty/whitespace-only text strings
continue

lc_message = value.to_lc_message()
messages.append(lc_message)

return messages

async def run_agent(
self,
agent: Runnable | BaseSingleActionAgent | BaseMultiActionAgent | AgentExecutor,
Expand Down Expand Up @@ -153,12 +171,14 @@ async def run_agent(

if hasattr(self, "chat_history") and self.chat_history:
if isinstance(self.chat_history, Data):
input_dict["chat_history"] = data_to_messages(self.chat_history)
input_dict["chat_history"] = self._data_to_messages_skip_empty(self.chat_history)

# Handle both lfx.schema.message.Message and langflow.schema.message.Message types
if all(hasattr(m, "to_data") and callable(m.to_data) and "text" in m.data for m in self.chat_history):
input_dict["chat_history"] = data_to_messages(self.chat_history)
input_dict["chat_history"] = self._data_to_messages_skip_empty(self.chat_history)

if all(isinstance(m, Message) for m in self.chat_history):
input_dict["chat_history"] = data_to_messages([m.to_data() for m in self.chat_history])
input_dict["chat_history"] = self._data_to_messages_skip_empty([m.to_data() for m in self.chat_history])

if (
hasattr(lc_message, "content")
Expand All @@ -169,7 +189,6 @@ async def run_agent(

if lc_message and hasattr(lc_message, "content") and isinstance(lc_message.content, list):
# ! Because the input has to be a string, we must pass the images in the chat_history

image_dicts = [item for item in lc_message.content if item.get("type") == "image"]
lc_message.content = [item for item in lc_message.content if item.get("type") != "image"]
text_content = [item for item in input_dict["input"].content if item.get("type") != "image"]
Expand Down
7 changes: 1 addition & 6 deletions src/backend/base/langflow/base/agents/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,7 @@ def data_to_messages(data: list[Data]) -> list[BaseMessage]:
Returns:
List[Message]: The data as messages.
"""
messages = []
for value in data:
# Skip messages with empty or None text to avoid errors with some model providers
if hasattr(value, "text") and value.text and str(value.text).strip():
messages.append(value.to_lc_message())
return messages
return [value.to_lc_message() for value in data]


def validate_and_create_xml_agent(
Expand Down
20 changes: 6 additions & 14 deletions src/backend/tests/unit/components/agents/test_agent_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,25 +544,18 @@ async def test_handle_on_chain_stream_no_output():
assert isinstance(start_time, float)

async def test_agent_streaming_no_text_accumulation():
"""Test that agent streaming sends individual token events without accumulating text."""
"""Test that agent streaming sends individual chunks without accumulating text."""
sent_messages = []
token_events = []

async def mock_send_message(message):
# Capture each message sent for verification
sent_messages.append(
{"text": message.text, "state": message.properties.state, "id": getattr(message, "id", None)}
)
sent_messages.append({
'text': message.text,
'state': message.properties.state,
'id': getattr(message, 'id', None)
})
return message

# Mock event manager to capture token events
class MockEventManager:
def on_token(self, data):
# Capture token events
token_events.append(data)

event_manager = MockEventManager()

agent_message = Message(
sender=MESSAGE_SENDER_AI,
sender_name="Agent",
Expand Down Expand Up @@ -616,7 +609,6 @@ def on_token(self, data):
assert result.properties.state == "complete"
assert result.text == "Hello world!"


async def test_agent_streaming_without_event_manager():
"""Test that agent streaming works without event_manager (backward compatibility)."""
sent_messages = []
Expand Down