fix: don't send duplicate messages to Agent#8909
Conversation
…mory data retrieval * Refactor MessageTextInput to MessageInput for consistency. * Enhance input dictionary construction to handle different input types in LCAgentComponent. * Update get_memory_data method to filter out current input value from retrieved messages.
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis change updates the agent input handling and memory retrieval logic across the core agent component and multiple starter project configurations. It standardizes the input type, refines how input values are processed, and modifies the memory retrieval method to exclude the current input message from the agent's chat history, preventing self-reference or duplication. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant AgentComponent
participant MemoryComponent
User->>AgentComponent: Provide input (MessageInput)
AgentComponent->>AgentComponent: If input is Message, extract text
AgentComponent->>MemoryComponent: Retrieve chat history
MemoryComponent-->>AgentComponent: Return messages
AgentComponent->>AgentComponent: Filter out message with same id as input_value
AgentComponent->>AgentComponent: Process agent logic with filtered memory
AgentComponent-->>User: Return agent response
Suggested labels
Suggested reviewers
✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 0
🔭 Outside diff range comments (11)
src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json (1)
868-915:get_memory_datasilently keeps non-Message objects – add a type-check guard
messagescan come back with system artefacts (strings, dicts, etc.) when custom Memories are plugged in.
The list-comprehension currently filters only byid, so a non-Messageelement with noidattribute will slip through and later break the agent when it expects.text,.role, etc.- return [ - message for message in messages - if getattr(message, "id", None) != getattr(self.input_value, "id", None) - ] + return [ + m for m in messages + if isinstance(m, Message) # ensure correct type + and getattr(m, "id", None) != getattr(self.input_value, "id", None) + ]Keeps the behaviour but prevents type errors further down the chain.
src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json (2)
1516-1540: Out-of-date import & type name – switch toMessageInputThe PR narrative says
MessageTextInputwas refactored toMessageInput, yet the embeddedAgentComponentcode still:from langflow.io import (..., MessageTextInput, ...)Keeping the old name will break once
MessageTextInputdisappears from the public API.-from langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output, MessageTextInput +from langflow.io import ( + BoolInput, + DropdownInput, + IntInput, + MultilineInput, + Output, + MessageInput, # <- new +)Follow up: replace every remaining
MessageTextInput(occurrence in this file withMessageInput(.
1600-1625:get_memory_dataonly excludes a singleinput_value– lists slip throughreturn [ message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None) ]When
input_valueis a list of messages,getattr(list, "id", None)is alwaysNone, so no messages are filtered out.
Consider handling the list case explicitly:-if getattr(message, "id", None) != getattr(self.input_value, "id", None) +excluded_ids = { + getattr(m, "id", None) for m in ( + self.input_value if isinstance(self.input_value, list) else [self.input_value] + ) +} +if getattr(message, "id", None) not in excluded_idsThis keeps the history clean regardless of how
input_valueis supplied.src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json (1)
2690-2705: Guard against unintended history purge wheninput_value.idisNone
get_memory_dataunconditionally filters on
getattr(m, "id", None) != getattr(self.input_value, "id", None).If the current
input_valuehasn’t been persisted yet,getattr(self.input_value,"id",None)isNone.
Any stale messages that also lack anid(e.g. synthetic or test messages) would then be discarded, silently wiping part—or all—of the chat history.A safer pattern:
- return [ - message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None) - ] + input_id = getattr(self.input_value, "id", None) + # Only filter when current input has a valid id + if input_id is None: + return messages + return [m for m in messages if getattr(m, "id", None) != input_id]Minor, but it eliminates a hard-to-trace edge case while keeping O(n) complexity.
src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json (1)
526-548: Replace deprecatedMessageTextInputwithMessageInputthroughout the starter project
MessageTextInputwas renamed toMessageInputin the core library in this PR.
Keeping the old_input_typehere will break runtime deserialization for every Agent/Prompt node that still references the old class (input_value,tool_placeholder, etc.).-"_input_type": "MessageTextInput", +"_input_type": "MessageInput",Please update all occurrences in the JSON (three shown here, but many more exist in other nodes) or run an automated find-&-replace before shipping the template.
Failure to do so will raiseValueError: unknown input_type 'MessageTextInput'when the flow is loaded.Also applies to: 1078-1098, 2422-2442
src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json (1)
1765-1785:retrieve_messages()result is not awaited – potential coroutine leak
retrieve_messages()is invoked immediately after.set(...), but the returned value is assigned without awaiting.
Ifretrieve_messages()is anasyncmethod (very likely, since it usually hits the DB), the current statement will assign a coroutine object instead of the actual list of messages, and the later list-comprehension will silently iterate over an empty list.- messages = ( - await MemoryComponent(**self.get_base_args()) - .set(session_id=self.graph.session_id, order="Ascending", n_messages=self.n_messages) - .retrieve_messages() - ) + memory_component = await MemoryComponent(**self.get_base_args()) + memory_component = memory_component.set( + session_id=self.graph.session_id, + order="Ascending", + n_messages=self.n_messages, + ) + messages = await memory_component.retrieve_messages()Failing to await here will surface only at runtime and is hard to trace; please double-check the signature of
retrieve_messages()and add the missingawaitif needed.src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json (2)
660-706: Update deprecatedMessageTextInputreferences toMessageInput.
MessageTextInputwas renamed in this PR, yet the template still lists it several times (background_color,chat_icon, etc.). Keeping the old enum will break dynamic form generation at runtime and produces a “component type not found” error.Typical fix for each occurrence:
- "_input_type": "MessageTextInput", + "_input_type": "MessageInput",Please sweep the file (and the other starter-project JSONs) for the old value and replace it consistently.
1461-1483:input_valuefield still uses the obsolete input type / wrong scalar type.Inside the Agent node:
"_input_type": "MessageTextInput", "type": "str", "input_types": ["Message"],
_input_typeshould beMessageInput(see previous comment).typeshould be"Message"(or be omitted) to keep the static-typing contract between the ChatInput output and the Agent input. Leaving it as"str"forces an implicit cast and silently discards metadata/files attached to the message.- "_input_type": "MessageTextInput", - "type": "str", + "_input_type": "MessageInput", + "type": "Message",Mis-typing here will surface as “invalid message format” when the Agent tries to access
.idor.files.src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json (2)
1340-1375:awaitprecedence may skip awaitingretrieve_messages()messages = ( await MemoryComponent(**self.get_base_args()) .set(session_id=self.graph.session_id, order="Ascending", n_messages=self.n_messages) .retrieve_messages() )Because attribute access and function calls bind tighter than
await, the expression is parsed as:await (MemoryComponent(**...).set(...).retrieve_messages())…so you ARE awaiting
retrieve_messages(), notMemoryComponent(...).
IfMemoryComponent.__call__(i.e. instantiation) or.set()returns an awaitable, those awaits are skipped.To remove any ambiguity:
mem = await MemoryComponent(**self.get_base_args()) mem = mem.set(session_id=self.graph.session_id, order="Ascending", n_messages=self.n_messages) messages = await mem.retrieve_messages()This guarantees every coroutine is awaited and eases future refactors.
1376-1384: Filtering out current input looks good but missesNoneIDs
getattr(message, "id", None) != getattr(self.input_value, "id", None)
works, but when both IDs areNone(e.g. legacy messages without IDs) the message is wrongly excluded.- return [ - message for message in messages - if getattr(message, "id", None) != getattr(self.input_value, "id", None) - ] + current_id = getattr(self.input_value, "id", object()) + return [m for m in messages if getattr(m, "id", object()) != current_id]Using a unique sentinel avoids accidental drops.
src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json (1)
1025-1035: Possible over-filtering inget_memory_datawheninput_valuelacks anidIf
self.input_valueis astr, a list, or aMessagewithout anid, the RHS of the comparison resolves toNone.
The current list-comprehension will then silently drop every past message whoseidis alsoNone, shrinking the chat history and potentially degrading the agent’s performance.- return [ - message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None) - ] + input_ids = ( + {getattr(m, "id", None) for m in self.input_value} + if isinstance(self.input_value, list) + else {getattr(self.input_value, "id", None)} + ) + return [msg for msg in messages if getattr(msg, "id", None) not in input_ids]• Handles list inputs
• Keeps historical messages whoseidisNonebut are not the current input.
♻️ Duplicate comments (4)
src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json (2)
2566-2586: SameMessageInputupgrade applied hereThe
LanguageModelComponenttemplate now usesMessageInputforinput_value, matching the Python definition further up. No issues spotted.
2859-2880: Same change replicated for second LLM nodeIdentical reasoning as previous comment — consistent and correct.
src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json (2)
2379-2410: Duplicate of the previousget_memory_datablock – same refactor/comments apply.
2923-2950: Duplicate of the previousget_memory_datablock – same refactor/comments apply.
🧹 Nitpick comments (10)
src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json (1)
1541-1555: Remove dead code:memory_inputsis defined but never used
memory_inputsis created:memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]but later commented-out in the
inputslist. This leaves an unused variable, raising linter warnings and confusing readers.-# ❶ remove the whole definition – it’s now obsolete -memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs] - -# (...) - # removed memory inputs from agent component - # *memory_inputs,If you plan to re-enable memory customization, keep the variable and add it back to
inputs; otherwise delete it entirely.src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json (1)
2080-2105: Guard againstNoneIDs when filtering chat history
get_memory_datanow excludes the currentinput_valuefrom history via[message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None)]If either side lacks an
id, the comparison falls back toNone, letting everymessagewhoseidis alsoNonepass through, potentially re-introducing duplicates for storages that never assign IDs.- return [ - message for message in messages - if getattr(message, "id", None) != getattr(self.input_value, "id", None) - ] + input_id = getattr(self.input_value, "id", object()) # sentinel avoids None collision + return [m for m in messages if getattr(m, "id", object()) != input_id]This preserves all messages with real IDs while reliably removing the current one.
src/backend/base/langflow/initial_setup/starter_projects/Market Research.json (2)
2170-2188: Hardenget_memory_datawith type-safety & empty-history guard
retrieve_messages()can theoretically returnNoneor an empty iterable.
Iterating over it immediately may raise or propagateTypeError.
A small guard also lets you add type hints & a doc-string for future readers.- async def get_memory_data(self): - messages = ( + async def get_memory_data(self) -> list[Message]: + """ + Fetch chat history and drop the message that triggered the call + to avoid echo-loops. + """ + messages: list[Message] | None = ( await MemoryComponent(**self.get_base_args()) .set(session_id=self.graph.session_id, order="Ascending", n_messages=self.n_messages) .retrieve_messages() ) - return [ - message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None) - ] + if not messages: + return [] + + return [ + m + for m in messages + if getattr(m, "id", None) != getattr(self.input_value, "id", None) + ]Benefits:
• AvoidsTypeErroronNonereturns.
• Adds explicit return type & docstring.
• Keeps comprehension readable.
2210-2228:AgentComponent.input_valuestill usesMessageTextInput– align with newMessageInputThe PR migrates to
MessageInputfor text-based message fields, yet this node definition remains on the deprecatedMessageTextInput.
Leaving it untouched means the agent path keeps the old behaviour while other components (e.g.ChatOutput,LanguageModelComponent) already expect the new input type – potential schema drift and UI inconsistency.Please verify and, if appropriate, switch:
-"_input_type": "MessageTextInput", +" _input_type": "MessageInput",to stay consistent with the rest of the template set.
src/backend/base/langflow/initial_setup/starter_projects/Search agent.json (1)
1135-1135: Consider extracting embedded Python code to separate files for better maintainability.Having large Python code blocks embedded within JSON configuration files makes code review, version control, and maintenance challenging. The embedded
AgentComponentclass is substantial and would benefit from being in a separate Python file.Consider refactoring to:
- Extract the
AgentComponentimplementation to a dedicated Python file- Reference the class by import path in the JSON configuration
- This would improve code maintainability, enable proper syntax highlighting, and make changes easier to review
src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json (1)
505-514: Minor optimisation inget_memory_datacomprehensionThe new filter works, but
getattr(self.input_value, "id", None)is recomputed for every loop iteration.- return [ - message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None) - ] + current_id = getattr(self.input_value, "id", None) + return [msg for msg in messages if getattr(msg, "id", None) != current_id]Not critical, yet shaves a method call per message and improves readability.
Also applies to: 540-547, 2388-2397
src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json (3)
1421-1470: Potential ordering confusion inget_memory_datamessages = ( await MemoryComponent(**self.get_base_args()) .set(session_id=self.graph.session_id, order="Ascending", n_messages=self.n_messages) .retrieve_messages() ) return [ message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None) ]Two things to verify:
Most LangChain agents expect history in chronological order (oldest → newest), but elsewhere in the codebase we traditionally fetched it descending and then reversed. Ensure downstream consumers aren’t accidentally seeing reversed context.
You rely on
iduniqueness to filter the current input. Ifself.input_valueis a string or any non-Message,getattr(..., "id", None)will beNone, so nothing is filtered. That’s fine, but be aware the optimisation only kicks in when the UI passes aMessageobject.
If that assumption is shaky, you could comparetextplus a timestamp hash instead.No change required if this behaviour is intentional.
1471-1505: Edge case:prefixmay beNonein_build_llm_modelfor input_ in inputs: if hasattr(self, f"{prefix}{input_.name}"): model_kwargs[input_.name] = getattr(self, f"{prefix}{input_.name}")
MODEL_PROVIDERS_DICTsetsprefixto""for most providers, but if a contributor adds a new provider and forgets the key,prefixcould beNone, leading toTypeError: can only concatenate str (not "NoneType") to str.Guard once upfront:
- for input_ in inputs: - if hasattr(self, f"{prefix}{input_.name}"): + prefix = prefix or "" + for input_ in inputs: + attr_name = f"{prefix}{input_.name}" + if hasattr(self, attr_name): model_kwargs[input_.name] = getattr(self, attr_name)
1506-1580:update_build_configis getting unwieldyThe method is pushing 150+ lines, merging concerns for:
- provider field switching
- dynamic input-type patching
- validation of mandatory keys
Consider extracting helper functions (e.g.,
_sync_provider_fields,_sanitize_input_types,_validate_default_keys) for readability and unit-testability.
This would also make future provider additions less error-prone.src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json (1)
1835-1860: Factor out duplicatedget_memory_dataand cover list inputsEach agent embeds the same block:
async def get_memory_data(self): messages = ( await MemoryComponent(**self.get_base_args()) .set(session_id=self.graph.session_id, order="Ascending", n_messages=self.n_messages) .retrieve_messages() ) return [ m for m in messages if getattr(m, "id", None) != getattr(self.input_value, "id", None) ]Issues:
- If
self.input_valueis a list ofMessages, only the first id is checked, so duplicates can re-enter history.- The identical definition is copied into three agents – any future tweak requires triple maintenance.
Suggested refactor (utility in a mixin or helper):
+def _exclude_current(messages, current): + if isinstance(current, list): + exclude_ids = {getattr(m, "id", None) for m in current} + else: + exclude_ids = {getattr(current, "id", None)} + return [m for m in messages if getattr(m, "id", None) not in exclude_ids] async def get_memory_data(self): messages = ( await MemoryComponent(**self.get_base_args()) .set(session_id=self.graph.session_id, order="Ascending", n_messages=self.n_messages) .retrieve_messages() ) - return [m for m in messages if getattr(m, "id", None) != getattr(self.input_value, "id", None)] + return _exclude_current(messages, self.input_value)This removes duplication and handles list/None cases cleanly.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
src/backend/base/langflow/base/agents/agent.py(3 hunks)src/backend/base/langflow/components/agents/agent.py(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Market Research.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Search agent.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json(3 hunks)src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json(3 hunks)src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
`src/backend/base/langflow/components/**/*.py`: Add new backend components to th...
src/backend/base/langflow/components/**/*.py: Add new backend components to the appropriate subdirectory under src/backend/base/langflow/components/
Implement async component methods using async def and await for asynchronous operations
Use asyncio.create_task for background work in async components and ensure proper cleanup on cancellation
Use asyncio.Queue for non-blocking queue operations in async components and handle timeouts appropriately
📄 Source: CodeRabbit Inference Engine (.cursor/rules/backend_development.mdc)
List of files the instruction was applied to:
src/backend/base/langflow/components/agents/agent.py
`src/backend/**/*.py`: Run make format_backend to format Python code early and often Run make lint to check for linting issues in backend Python code
src/backend/**/*.py: Run make format_backend to format Python code early and often
Run make lint to check for linting issues in backend Python code
📄 Source: CodeRabbit Inference Engine (.cursor/rules/backend_development.mdc)
List of files the instruction was applied to:
src/backend/base/langflow/components/agents/agent.pysrc/backend/base/langflow/base/agents/agent.py
`src/backend/**/components/**/*.py`: In your Python component class, set the `icon` attribute to a string matching the frontend icon mapping exactly (case-sensitive).
src/backend/**/components/**/*.py: In your Python component class, set theiconattribute to a string matching the frontend icon mapping exactly (case-sensitive).
📄 Source: CodeRabbit Inference Engine (.cursor/rules/icons.mdc)
List of files the instruction was applied to:
src/backend/base/langflow/components/agents/agent.py
🧠 Learnings (2)
src/backend/base/langflow/base/agents/agent.py (4)
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-06-30T14:41:58.849Z
Learning: Applies to {src/backend/tests/**/*.py,tests/**/*.py} : Test Langflow's 'Message' objects and chat functionality by asserting correct properties and structure.
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-06-30T14:39:17.464Z
Learning: Applies to src/backend/base/langflow/components/**/__init__.py : Update __init__.py with alphabetical imports when adding new components
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-06-30T14:39:17.464Z
Learning: Applies to src/backend/base/langflow/components/**/*.py : Add new backend components to the appropriate subdirectory under src/backend/base/langflow/components/
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-06-30T14:41:58.849Z
Learning: Applies to {src/backend/tests/**/*.py,tests/**/*.py} : Test backward compatibility across Langflow versions by mapping component files to supported versions using 'VersionComponentMapping'.
src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json (1)
undefined
<retrieved_learning>
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-06-30T14:39:17.464Z
Learning: Starter project files are auto-formatted after langflow run; these changes can be committed or ignored
</retrieved_learning>
🧬 Code Graph Analysis (1)
src/backend/base/langflow/base/agents/agent.py (4)
src/backend/base/langflow/inputs/inputs.py (1)
MessageInput(187-202)src/backend/base/langflow/schema/data.py (1)
get_text(60-69)src/backend/tests/unit/custom/custom_component/test_component_events.py (1)
get_text(28-30)src/backend/base/langflow/schema/message.py (1)
Message(39-289)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Optimize new Python code in this PR
- GitHub Check: Run Ruff Check and Format
- GitHub Check: Update Starter Projects
- GitHub Check: Ruff Style Check (3.13)
🔇 Additional comments (16)
src/backend/base/langflow/components/agents/agent.py (1)
129-136: Excellent fix for memory data filtering!This change successfully addresses the issue where the current input message was being included in the agent's chat history, causing calculation errors like
2+2becoming2+22+2. The filtering logic correctly excludes the current input message from the retrieved memory data.The implementation uses defensive programming with
getattr(message, "id", None)to handle cases where messages might not have anidattribute, which is robust and prevents potential AttributeError exceptions.src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json (1)
1127-1127: Consistent implementation across starter projects!The embedded AgentComponent code correctly mirrors the memory filtering changes from the main agent component. This ensures that users starting with the Simple Agent template will benefit from the same fix that prevents input message duplication in chat history.
Maintaining consistency between the core components and starter project templates is crucial for providing a uniform user experience.
src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json (1)
1564-1586:input_valueswitched toMessageInput– verify it still accepts edge connectionsThe field is now declared as
"_input_type": "MessageInput", "input_types": ["Data", "DataFrame", "Message"],
MessageInputis a literal text-box input and, unlikeHandleInput, is not meant to accept incoming links.
However this node is wired to Agent-JRSRu → ChatOutput-vlskP viainput_value, so the editor will attempt to connect a handle here.Double-check that the underlying UI component was updated so
MessageInputcan act as a handle target; otherwise the edge will be refused at runtime and the flow will break.If linkage is still required, keep the field as
HandleInput(or the newMessageHandleInputcounterpart) instead ofMessageInput.src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json (1)
1626-1640: Minor: defensive check forretrieve_messagesawait-ability
retrieve_messages()is called inside the awaited expression:messages = ( await MemoryComponent(**self.get_base_args()) .set(...).retrieve_messages() )If
retrieve_messagesever becomes async itself this works, but if it is sync returning a list, the whole expression is still fine.
Just ensure tests cover both sync/async implementations—or add a comment clarifying thatretrieve_messagesreturns an awaitable.src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json (1)
1151-1173: Template field switched toMessageInput—looks correctChanging
_input_typefromMessageTextInputtoMessageInputaligns the UI control with the new input-handling changes inChatOutput.input_typesstill allowData/DataFrame/Message, so existing flows stay compatible.src/backend/base/langflow/initial_setup/starter_projects/Market Research.json (1)
618-640: ConfirmChatOutput’sinput_valuetyping after the switch toMessageInput
_input_typehas been updated to"MessageInput"but the underlyingtypefield is still"str".
IfMessageInputcan emit objects other than plain strings (e.g. fullMessageinstances), the"str"declaration may break validation or downstream assumptions.Double-check the expected payload of
MessageInputand adjusttype/input_typesaccordingly to avoid runtime coercion surprises.src/backend/base/langflow/initial_setup/starter_projects/Search agent.json (1)
1135-1135: Memory filtering logic is correctly implementedThe
get_memory_datamethod excludes the current input message by comparingmessage.idtoself.input_value.id, as intended:• It returns
[message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None)]
which correctly filters out the current input message.No further changes are needed for this logic.
src/backend/base/langflow/base/agents/agent.py (3)
15-15: LGTM: Import update aligns with improved input handling.The change from
MessageTextInputtoMessageInputis appropriate. Based on the relevant code snippets,MessageInputprovides more robust validation and can handle various input types (dict, Message, str, iterators) while converting them to properMessageinstances.
37-42: LGTM: Input type change is consistent with the import update.The change from
MessageTextInputtoMessageInputin the_base_inputsdefinition is consistent with the import change and maintains proper typing for the input field.
138-140: Approved: Input handling for Message instances is correctConfirmed that
Message.get_text()is inherited fromData.get_text()insrc/backend/base/langflow/schema/data.py, which reliably returns the message’s text (or the default empty string). No further changes are needed.src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json (1)
581-603: Inconsistent_input_typeupdate – verify front-end binding
input_valuewas switched fromMessageTextInputtoMessageInputfor theChatOutputcomponent.
Other components (e.g.Agentstill usingMessageTextInput) remain unchanged. Make sure the UI side renders the proper widget and that the back-end validation layer recognises both types, otherwise users may hit a “value is not a valid xxx” error when wiring nodes.No change is required in this JSON, but please confirm the new
_input_typeis supported across the whole stack.src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json (1)
1441-1500: Edge-case inget_memory_datafilter – string inputs leak through.return [ message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None) ]If
self.input_valueis a plainstr(user passes raw text instead of aMessage),getattr(self.input_value,"id",None)returnsNone.
All stored messages whoseidis alsoNone(e.g., legacy rows or system prompts) will be wrongly excluded.Consider making the comparison only when
self.input_valueis aMessage:- if getattr(message, "id", None) != getattr(self.input_value, "id", None) + if not isinstance(self.input_value, Message) or message.id != self.input_value.idThat prevents accidental loss of messages and keeps the intention clear.
src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json (1)
557-579: Confirm frontend support for newMessageInputtypeThe
_input_typeforinput_valuewas changed fromMessageTextInputtoMessageInput.
Double-check that:
- The React component registry already maps
MessageInputto a rendered control.- Existing starter projects or user flows that persist
MessageTextInputdon’t break on load/migration.If runtime compatibility is a concern, you might temporarily allow both aliases or run a migration script that rewrites stored flows.
src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json (1)
429-435: Confirm backend support for newly-renamedMessageInputtype
"_input_type": "MessageInput"replaces the previousMessageTextInput.
Please double–check that:
- The front-end schema recognises
MessageInput(autocompletion, validation, etc.).- All components that still emit/expect the old
MessageTextInputtype were refactored accordingly, otherwise drag-and-drop wiring in the UI will silently break.If this is just an alias, adding a short migration helper (e.g. accept both names for one release) could avoid regressions for existing custom templates.
src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json (1)
1025-1027: StaleMessageTextInputreference will break once the rename toMessageInputlandsThe PR description says
MessageTextInputwas refactored toMessageInput, yet this embedded component still imports and instantiates the old class. When the alias is removed, this starter project will fail to load.Update the import and the input declaration:
-from langflow.io import MessageTextInput, Output, PromptInput +from langflow.io import MessageInput, Output, PromptInput ... - MessageTextInput( + MessageInput(Run a quick grep over the starter projects to ensure no other lingering references remain.
⛔ Skipped due to learnings
Learnt from: CR PR: langflow-ai/langflow#0 File: .cursor/rules/backend_development.mdc:0-0 Timestamp: 2025-06-30T14:39:17.464Z Learning: Starter project files are auto-formatted after langflow run; these changes can be committed or ignoredLearnt from: CR PR: langflow-ai/langflow#0 File: .cursor/rules/backend_development.mdc:0-0 Timestamp: 2025-06-30T14:39:17.464Z Learning: Applies to src/backend/base/langflow/components/**/__init__.py : Update __init__.py with alphabetical imports when adding new componentsLearnt from: CR PR: langflow-ai/langflow#0 File: .cursor/rules/icons.mdc:0-0 Timestamp: 2025-06-23T12:46:52.420Z Learning: When implementing a new component icon in Langflow, ensure the icon name is clear, recognizable, and used consistently across both backend (Python 'icon' attribute) and frontend (React/TypeScript mapping).Learnt from: CR PR: langflow-ai/langflow#0 File: .cursor/rules/testing.mdc:0-0 Timestamp: 2025-06-30T14:41:58.849Z Learning: Applies to {src/backend/tests/**/*.py,tests/**/*.py} : Test Langflow's 'Message' objects and chat functionality by asserting correct properties and structure.src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json (1)
650-672: Inconsistent_input_typerename – verify front-end compatibility
ChatOutput.input_valuenow uses_input_type": "MessageInput"while other nodes (e.g.ChatInput, allAgentnodes) still rely on"MessageTextInput".
If the UI/backend doesn’t recognise both aliases, drag-and-drop wiring or validation might silently fail.Please confirm that
MessageInputis registered as a component type, and- legacy
MessageTextInputreferences are either migrated or kept as backward-compatible shims.Failing to do so will break existing flows once they’re re-saved.
|
testing |
| ) | ||
| input_dict: dict[str, str | list[BaseMessage]] = {"input": self.input_value} | ||
| input_dict: dict[str, str | list[BaseMessage]] = { | ||
| "input": self.input_value.get_text() if isinstance(self.input_value, Message) else self.input_value |
There was a problem hiding this comment.
@ogabrielluiz I believe @Cristhianzl was making changes to ensure the images work with agents.
Won't this be in conflict with that, since we are getting only the text inputs.
There was a problem hiding this comment.
It was already getting text inputs before. I can fix that in another PR as this is aimed getting it back to a working state.
|
@ogabrielluiz The issue still persists. |
|
@coderabbitai, Even if we do the following: The input seems repeated. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain@edwinjosechittilappilly Thank you for testing and confirming the issue persists. Let me investigate the implementation to identify why the input duplication is still occurring. 🏁 Script executed: Length of output: 23793 Let me examine the Simple Agent template implementation and check for potential issues with the filtering logic: 🏁 Script executed: Length of output: 3913 🏁 Script executed: Length of output: 10447 🏁 Script executed: Length of output: 5151 🏁 Script executed: Length of output: 19782 🏁 Script executed: Length of output: 13041 🏁 Script executed: Length of output: 11831 @edwinjosechittilappilly I've found the root cause of the issue! The problem is that the Message class doesn't have an Looking at the current filtering code: return [
message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None)
]Since Here's the fix needed: Fix: Replace ID-based filtering with message content comparison
This fix compares the actual message content (text, timestamp, and sender) instead of relying on non-existent ID fields, which should properly filter out the current input message from the chat history. ⏳ Preparing changes... |
|
A summary of the changes CodeRabbit can apply:
A summary of the context that CodeRabbit is considering across the codebase:
Show context detailsShell Result: Examine the Message class fields to understand what's available for comparisongrep -A 20 "class Message(Data):" src/backend/base/langflow/schema/message.py class Message(Data):
Show context detailsShell Result: Check the input_value field definition in the base agent componentgrep -A 10 -B 5 "MessageInput.*input_value" src/backend/base/langflow/base/agents/agent.py class LCAgentComponent(Component):
Show context detailsShell Result: Look at the current filtering logic in get_memory_datagrep -A 5 -B 5 "getattr.*id.*None" src/backend/base/langflow/components/agents/agent.py
Show context detailsShell Result: Search for message comparison patterns in the codebaserg -A 3 -B 3 "message.text.*message.timestamp|message.timestamp.*message.text" src/backend/base/langflow/ src/backend/base/langflow/components/helpers/memory.py- data = {"text": message.text, "timestamp": message.timestamp}
|
What did you do to reproduce it? Did you update the component? |
…input handling * Added documentation link for AgentComponent. * Removed memory inputs from the agent component for cleaner input management. * Enhanced error handling in message_response method to ensure better validation and logging of exceptions.
edwinjosechittilappilly
left a comment
There was a problem hiding this comment.
LGTM, Fix looks ok, lets add tests and further stability fixes post release.
…onversion * Updated input dictionary construction in LCAgentComponent to use to_lc_message() for Message instances, improving input handling consistency.
* Updated the sender validation logic in the Message class to remove unnecessary checks for missing sender values. * This change enhances code clarity and maintains the intended functionality for handling user messages with associated files.
* Modified the test for message conversion to assert that lc_message.content is a string instead of a list. * Updated assertions to ensure the content matches the expected text, enhancing test accuracy and reliability.
* Modified the sender validation logic to handle cases where the sender is not specified, defaulting to HumanMessage. * Updated the corresponding test case to reflect this change, ensuring accurate type assertion for lc_message when no sender is provided.
* Replaced the import of BaseModel from langchain.pydantic_v1 with the direct import from pydantic to streamline dependencies. * This change enhances code clarity and aligns with best practices for managing imports in the codebase.
* fix: update message input handling in LCAgentComponent and improve memory data retrieval * Refactor MessageTextInput to MessageInput for consistency. * Enhance input dictionary construction to handle different input types in LCAgentComponent. * Update get_memory_data method to filter out current input value from retrieved messages. * fix: update AgentComponent to include documentation link and improve input handling * Added documentation link for AgentComponent. * Removed memory inputs from the agent component for cleaner input management. * Enhanced error handling in message_response method to ensure better validation and logging of exceptions. * fix: enhance input handling in LCAgentComponent by updating message conversion * Updated input dictionary construction in LCAgentComponent to use to_lc_message() for Message instances, improving input handling consistency. * test: add regression test for message duplication in agent component * Introduced a new test to verify that mathematical expressions do not experience message duplication when processed by the agent component. * The test checks both input and output JSON to ensure correct handling of expressions like "2+2" without duplication errors. * test: add workspace tag to regression test for message duplication in agent component * Updated the regression test for mathematical expressions to include the "@workspace" tag, enhancing test categorization and organization. * This change ensures better tracking and management of tests related to the agent component. * fix: add temporary comment in get_memory_data to address message duplication * Added a TODO comment in the get_memory_data method of AgentComponent to indicate a temporary fix for message duplication issues. This serves as a reminder to develop a more robust solution in the future. * feat: add message extraction utility for BaseMessage * Introduced a new helper function, _get_message_from_base_message, to extract and concatenate text content from BaseMessage instances, improving message handling. * Updated input handling in handle_on_chain_start to utilize the new extraction function, ensuring consistent processing of input messages. * refactor: standardize code snippets across starter project JSON files * Updated the "value" field in multiple starter project JSON files to ensure consistent formatting and structure of code snippets. * This change enhances readability and maintainability of the code examples provided in the starter projects. * feat: add caching and content dictionary creation for images * Introduced a new function, create_image_content_dict, to generate a content dictionary for multimodal inputs from image files, enhancing image handling capabilities. * Implemented LRU caching to optimize performance for repeated image processing. * Added comprehensive error handling and documentation for better usability and maintainability. * refactor: update message handling to utilize create_image_content_dict * Replaced direct image URL creation with create_image_content_dict for improved image content handling in the Data and Message classes. * Adjusted the order of content in human messages to ensure text appears first, enhancing message structure and clarity. * Removed deprecated to_lc_message method to streamline the codebase and improve maintainability. * docs: enhance _get_message_from_base_message docstring for clarity * Expanded the docstring for the _get_message_from_base_message function to provide detailed information on input types, expected behavior, and examples of usage. * Improved documentation aims to enhance usability and maintainability of the code by clarifying how to extract text content from BaseMessage instances. * refactor: enhance image path handling and update message content structure * Modified the get_file_paths function to support both Image objects and string paths for improved flexibility in file handling. * Updated test cases to reflect changes in image content structure, ensuring consistency in type and source type attributes. * Introduced new tests for create_image_content_dict to validate successful creation and error handling for image content dictionaries. * refactor: streamline message extraction in handle_on_chain_start * Removed the _get_message_from_base_message function to simplify the codebase. * Updated handle_on_chain_start to directly use the text method of BaseMessage for extracting message content, enhancing clarity and maintainability. * feat: enhance input handling for multimodal messages * Added functionality to process image content within input messages, ensuring images are included in chat history as HumanMessage instances. * Updated input handling logic to separate image types from text, improving the structure and clarity of message content. * This enhancement supports better management of multimodal inputs in the agent's chat history. * feat: add to_lc_message method for converting Data to BaseMessage * Introduced the to_lc_message method in the Message class to facilitate conversion of Data instances to BaseMessage. * Implemented logic to handle both HumanMessage and AIMessage based on the presence of required keys and sender type. * Added logging for missing required keys to improve debugging and maintainability. * refactor: simplify sender check in Message class * Updated the sender validation logic in the Message class to remove unnecessary checks for missing sender values. * This change enhances code clarity and maintains the intended functionality for handling user messages with associated files. * test: update test_message_from_human_text to reflect content type change * Modified the test for message conversion to assert that lc_message.content is a string instead of a list. * Updated assertions to ensure the content matches the expected text, enhancing test accuracy and reliability. * fix: update sender validation in Message class and adjust test case * Modified the sender validation logic to handle cases where the sender is not specified, defaulting to HumanMessage. * Updated the corresponding test case to reflect this change, ensuring accurate type assertion for lc_message when no sender is provided. * refactor: update import statements for consistency and clarity * Replaced the import of BaseModel from langchain.pydantic_v1 with the direct import from pydantic to streamline dependencies. * This change enhances code clarity and aligns with best practices for managing imports in the codebase. --------- Co-authored-by: Edwin Jose <edwin.jose@datastax.com> Co-authored-by: Carlos Coelho <80289056+carlosrcoelho@users.noreply.github.com>
When using Anthropic models if you pass a message like
2+2in the Simple Agent template, it would calculate2+22+2. This fixes that issue.Summary by CodeRabbit
Bug Fixes
Enhancements