fix: Image upload for Gemini/Anthropic#10867
Conversation
|
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 PR updates ChatOutput components across 24 starter project JSONs to preserve incoming Message session_ids when reusing existing messages, along with standardizing image content format in LFx to always use "image_url" type and supporting both legacy and standard image formats in multimodal agent handling. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touchesImportant Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 1 warning, 2 inconclusive)
✅ Passed checks (3 passed)
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. Comment |
Codecov Report❌ Patch coverage is
❌ Your patch status has failed because the patch coverage (14.28%) is below the target coverage (40.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #10867 +/- ##
==========================================
- Coverage 32.55% 32.54% -0.01%
==========================================
Files 1370 1370
Lines 63544 63543 -1
Branches 9394 9394
==========================================
- Hits 20685 20680 -5
- Misses 41820 41825 +5
+ Partials 1039 1038 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json (1)
4190-4210: Fix runtime TypeError: replace PEP 604 unions with tuple-based isinstance checks.
isinstance(x, A | B)raisesTypeErrorat runtime in Python 3.10+. Use tuples instead:- if isinstance(self.input_value, list) and not all( - isinstance(item, Message | Data | DataFrame | str) for item in self.input_value - ): + valid_item_types = (Message, Data, DataFrame, str) + if isinstance(self.input_value, list) and not all( + isinstance(item, valid_item_types) for item in self.input_value + ): invalid_types = [ type(item).__name__ - for item in self.input_value - if not isinstance(item, Message | Data | DataFrame | str) + for item in self.input_value + if not isinstance(item, valid_item_types) ] msg = f"Expected Data or DataFrame or Message or str, got {invalid_types}" raise TypeError(msg) - if not isinstance( - self.input_value, - Message | Data | DataFrame | str | list | Generator | type(None), - ): + valid_types = (Message, Data, DataFrame, str, list, Generator, type(None)) + if not isinstance(self.input_value, valid_types): type_name = type(self.input_value).__name__ msg = f"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}" raise TypeError(msg)This pattern also appears in
src/lfx/src/lfx/components/input_output/chat_output.py(lines 165, 170) andsrc/backend/base/langflow/services/chat/cache.pyand should be fixed identically.src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json (1)
639-739: Don’t overwrite context_id/flow_id; preserve like session_id.When reusing an incoming Message you overwrite context_id (and possibly flow_id), losing existing context. Mirror the session_id precedence for these fields.
Apply this diff inside message_response:
- message.context_id = self.context_id - message.flow_id = self.graph.flow_id if hasattr(self, "graph") else None + # Preserve existing context/flow if component values are not provided + message.context_id = self.context_id or getattr(message, "context_id", None) or "" + message.flow_id = ( + (self.graph.flow_id if hasattr(self, "graph") and getattr(self.graph, "flow_id", None) else None) + or getattr(message, "flow_id", None) + )Additionally, the _build_source signature says source: str | None but you pass model objects too. Consider widening the annotation:
- def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source: + def _build_source(self, id_: str | None, display_name: str | None, source: object | None) -> Source:src/lfx/src/lfx/utils/image.py (1)
58-79: Fix Ruff ARG001 by markingmodel_nameintentionally unused
create_image_content_dictnow ignoresmodel_namebut keeps it in the signature for backward compatibility, triggering Ruff’s ARG001 and breaking CI.You can satisfy Ruff without changing behavior or the public API:
@lru_cache(maxsize=50) def create_image_content_dict( image_path: str | Path, mime_type: str | None = None, model_name: str | None = None ) -> dict: @@ - """ - data_url = create_data_url(image_path, mime_type) - - # Standard format for OpenAI, Anthropic, Gemini, and most providers - # Format: {"type": "image_url", "image_url": {"url": "data:..."}} - return {"type": "image_url", "image_url": {"url": data_url}} + """ + # `model_name` is kept for backward compatibility with existing callers. + _ = model_name + data_url = create_data_url(image_path, mime_type) + + # Standard format for multimodal providers: + # {"type": "image_url", "image_url": {"url": "data:..."}} + return {"type": "image_url", "image_url": {"url": data_url}}This should clear the Ruff error while preserving the cached function’s call signature.
♻️ Duplicate comments (7)
src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json (2)
471-560: Same context preservation issue as in SEO template; apply the same fix.Replicate the context_id/flow_id preservation and _build_source annotation update suggested in the SEO Keyword Generator comment.
471-560: Verify Python version for union usage in isinstance.Same verification needed here.
#!/bin/bash # Reuse the version scan from the other comment fd -HIa 'pyproject.toml|poetry.lock|Pipfile|runtime.txt|Dockerfile|.python-version' \ | xargs -I{} sh -c 'echo "== {} =="; sed -n "1,160p" "{}" | rg -n "python|FROM .*python|requires-python|3\.[0-9]+"' || truesrc/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json (2)
383-470: Preserve context_id/flow_id; mirror the fix across templates.Avoid clobbering context by adopting the same precedence pattern used for session_id. Apply the same diff as proposed in the SEO file.
383-470: Confirm Python version compatibility for isinstance with unions.Same runtime check as above.
#!/bin/bash # Same scan as other comments; included here for convenience fd -HIa 'pyproject.toml|poetry.lock|Pipfile|runtime.txt|Dockerfile|.python-version' \ | xargs -I{} sh -c 'echo "== {} =="; sed -n "1,160p" "{}" | rg -n "python|FROM .*python|requires-python|3\.[0-9]+"' || truesrc/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json (2)
448-448: Same_build_sourcetyping/guard suggestion as in Market Research.Broaden
sourcetype and guard stringification to avoid runtime surprises with provider objects. See earlier diff for details.
448-448: Confirm Generator-to-storage path.As above, please verify that Message.text and send_message accept Generators; if not, coerce to str before storing.
src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json (1)
883-883: ChatOutput behavior matches the already-reviewed implementationThis
ChatOutputblock mirrors the implementation reviewed in the Basic Prompting starter:
- Same
code_hashandmessage_responselogic withexisting_session_idcapture and
component session_id → existing_session_id → graph.session_id → ""precedence.- Same convert/validation and storage behavior.
Given the identical implementation, the same reasoning applies here; the change is consistent and should fix session continuity for this flow as well.
Also applies to: 958-958
🧹 Nitpick comments (11)
src/backend/base/langflow/initial_setup/starter_projects/Nvidia Remix.json (1)
589-589: Guard against Generator being assigned to Message.text.
convert_to_string()may return aGenerator;message.text = textwill then be a generator object. Either stream explicitly or coerce tostrfor non‑streaming paths.Minimal safeguard:
- text = self.convert_to_string() + text = self.convert_to_string() + if isinstance(text, Generator): + # materialize or handle streaming before assigning to message.text + text = "".join(text)Alternatively, branch to a streaming pathway when
Generator.src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json (1)
718-719: Avoid mutating upstream Message in-place.When input_value is a Message, you mutate it (text/session_id). Safer to clone to avoid side effects on nodes that still hold a reference.
For example:
- message = self.input_value - message.text = text + original = self.input_value + message = Message(text=text) + # copy selective metadata + message.session_id = getattr(original, "session_id", None) + message.context_id = getattr(original, "context_id", None) + message.sender = getattr(original, "sender", self.sender) + message.sender_name = getattr(original, "sender_name", self.sender_name)src/backend/base/langflow/initial_setup/starter_projects/Custom Component Generator.json (2)
2316-2317: Optional: avoid mutating incoming Message.Prefer cloning the incoming Message rather than mutating in-place to prevent side effects in flows that reuse it elsewhere.
2316-2317: Optional: skip storage for generator text.If text is a Generator, either materialize it or skip send_message to avoid unexpected persistence.
src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json (1)
229-230: Good fix; mirror minor refinements and verify streaming text behavior.
- Keep: existing_session_id logic and session_id fallback chain.
- Type: change _build_source(source: str | None) → source: object | None (or Any).
- Safety: ensure message.properties exists before setting .source.
- Streaming: confirm Message.text and the Playground ChatOutput path accept a Generator; otherwise adjust.
Optional tests to lock behavior in:
- When input_value is Message and component is NOT connected to ChatInput, message_response preserves the inbound session_id.
- When connected to ChatInput, message_response uses graph.session_id (or component session_id) and messages appear in chat.
I can generate pytest snippets for these two cases if helpful.
src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json (1)
575-575: Avoid overwriting sender fields when reusing an existing Message.You always set message.sender and message.sender_name to component values, even when an incoming Message already has these set. Consider defaulting to the existing values if component inputs are empty to better preserve provenance.
- message.sender = self.sender - message.sender_name = self.sender_name + message.sender = self.sender or getattr(message, "sender", None) + message.sender_name = self.sender_name or getattr(message, "sender_name", None)src/backend/base/langflow/initial_setup/starter_projects/Market Research.json (2)
553-553: Broaden_build_sourcetyping and add a safer fallback.The parameter
source: str | Noneis narrower than actual usage (you access attributes like.model_name/.model). Recommend typing asAny(or a Protocol) and guarding stringification to avoid surprises.- def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source: + from typing import Any + def _build_source(self, id_: str | None, display_name: str | None, source: Any) -> Source: @@ - if source: - # Handle case where source is a ChatOpenAI object - if hasattr(source, "model_name"): - source_dict["source"] = source.model_name - elif hasattr(source, "model"): - source_dict["source"] = str(source.model) - else: - source_dict["source"] = str(source) + if source is not None: + try: + if hasattr(source, "model_name"): + source_dict["source"] = source.model_name + elif hasattr(source, "model"): + source_dict["source"] = str(source.model) + else: + source_dict["source"] = str(source) + except Exception: + source_dict["source"] = type(source).__name__
553-553: Verify Generator handling before storing messages.convert_to_string may return a Generator, which is then assigned to message.text and potentially passed to send_message. Confirm Message.text and storage support generators; otherwise coerce to str when storing.
- text = self.convert_to_string() + text = self.convert_to_string() + # If streaming (Generator), avoid storing as-is; coerce or skip store + from collections.abc import Generator as _Gen + is_stream = isinstance(text, _Gen) @@ - if message.session_id and self.should_store_message: + if message.session_id and self.should_store_message: + if is_stream: + # materialize for persistence; adjust if large streams are expected + text = "".join(list(text)) + message.text = text stored_message = await self.send_message(message)src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json (1)
2018-2067: Consider guarding access toself.graphin ChatInput.message_response
session_id = self.session_id or self.graph.session_id or ""assumesself.graphis always present. If this component is ever instantiated without a graph context (e.g., in tests or programmatic usage), this will raiseAttributeError.You can defensively guard this without changing behavior in normal flows:
- session_id = self.session_id or self.graph.session_id or "" + graph_session_id = getattr(getattr(self, "graph", None), "session_id", None) + session_id = self.session_id or graph_session_id or ""src/lfx/src/lfx/base/agents/altk_base_agent.py (1)
322-331: Harden image extraction against non-dict content blocksThe new logic correctly supports both
"image"and"image_url"content types and moves them intochat_history, but it assumes everylc_message.contentitem has.get, i.e., is adict. If any upstream code ever emits non-dict blocks, this will raise anAttributeError.You can make this more robust without changing behavior:
- image_dicts = [item for item in lc_message.content if item.get("type") in ("image", "image_url")] - lc_message.content = [item for item in lc_message.content if item.get("type") not in ("image", "image_url")] + image_dicts = [ + item + for item in lc_message.content + if isinstance(item, dict) and item.get("type") in ("image", "image_url") + ] + lc_message.content = [ + item + for item in lc_message.content + if not (isinstance(item, dict) and item.get("type") in ("image", "image_url")) + ]src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json (1)
467-554: ChatOutput update looks good; consider aligningstore_messagevsshould_store_messagenamingThe embedded
ChatOutputcode (includingexisting_session_idpreservation andsession_idprecedence) matches the core implementation and should behave correctly in this flow.One small nit: the node’s
field_orderstill refers to"store_message", while the corresponding input field is named"should_store_message". This is likely harmless but inconsistent and could confuse future changes or UI tooling. Consider renaming the field infield_orderto match the actual input key for clarity.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (34)
src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Custom Component Generator.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Hybrid Search RAG.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Knowledge Retrieval.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Market Research.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json(6 hunks)src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Nvidia Remix.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Search agent.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json(2 hunks)src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json(2 hunks)src/lfx/src/lfx/base/agents/agent.py(2 hunks)src/lfx/src/lfx/base/agents/altk_base_agent.py(1 hunks)src/lfx/src/lfx/components/input_output/chat_output.py(1 hunks)src/lfx/src/lfx/utils/image.py(1 hunks)src/lfx/tests/unit/schema/test_schema_data.py(2 hunks)src/lfx/tests/unit/schema/test_schema_message.py(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/test_*.py
📄 CodeRabbit inference engine (Custom checks)
**/test_*.py: Review test files for excessive use of mocks that may indicate poor test design - check if tests have too many mock objects that obscure what's actually being tested
Warn when mocks are used instead of testing real behavior and interactions, and suggest using real objects or test doubles when mocks become excessive
Ensure mocks are used appropriately for external dependencies only, not for core logic
Backend test files should follow the naming convention test_*.py with proper pytest structure
Test files should have descriptive test function names that explain what is being tested
Tests should be organized logically with proper setup and teardown
Consider including edge cases and error conditions for comprehensive test coverage
Verify tests cover both positive and negative scenarios where appropriate
For async functions in backend tests, ensure proper async testing patterns are used with pytest
For API endpoints, verify both success and error response testing
Files:
src/lfx/tests/unit/schema/test_schema_data.pysrc/lfx/tests/unit/schema/test_schema_message.py
🧠 Learnings (3)
📚 Learning: 2025-09-08T21:06:27.173Z
Learnt from: edwinjosechittilappilly
Repo: langflow-ai/langflow PR: 9745
File: src/backend/base/langflow/utils/image.py:102-102
Timestamp: 2025-09-08T21:06:27.173Z
Learning: OpenAI API uses image content format: `{"type": "image_url", "image_url": {"url": "data:mime_type;base64,..."}}` for vision-enabled models like GPT-4, GPT-4o, and GPT-4.1.
Applied to files:
src/lfx/src/lfx/utils/image.pysrc/lfx/tests/unit/schema/test_schema_data.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Test Langflow's `Message` objects using `langflow.schema.message.Message` and validate text, sender, sender_name, session_id, files, and properties attributes
Applied to files:
src/lfx/tests/unit/schema/test_schema_data.pysrc/lfx/tests/unit/schema/test_schema_message.py
📚 Learning: 2025-06-26T19:43:18.260Z
Learnt from: ogabrielluiz
Repo: langflow-ai/langflow PR: 0
File: :0-0
Timestamp: 2025-06-26T19:43:18.260Z
Learning: In langflow custom components, the `module_name` parameter is now propagated through template building functions to add module metadata and code hashes to frontend nodes for better component tracking and debugging.
Applied to files:
src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json
🧬 Code graph analysis (1)
src/lfx/src/lfx/components/input_output/chat_output.py (2)
src/lfx/src/lfx/schema/message.py (1)
Message(34-299)src/lfx/src/lfx/custom/custom_component/custom_component.py (1)
graph(191-192)
🪛 GitHub Actions: Ruff Style Check
src/lfx/src/lfx/utils/image.py
[error] 60-60: ARG001 Unused function argument: model_name (ruff check failed during 'uv run --only-dev ruff check --output-format=github .')
⏰ 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). (60)
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 41/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 37/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 40/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 46/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 48/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 50/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 42/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 49/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 45/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 38/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 44/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 43/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 47/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 39/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 36/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 33/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 31/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 35/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 34/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 21/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 28/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 27/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 30/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 26/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 32/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 25/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 29/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 17/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 19/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 24/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 23/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 18/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 22/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 16/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 20/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 4/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 12/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 15/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 6/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 8/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 9/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 1/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 14/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 13/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 5/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 11/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 7/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 10/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 2/50
- GitHub Check: Run Frontend Tests / Playwright Tests - Shard 3/50
- GitHub Check: Test Docker Images / Test docker images
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
- GitHub Check: Run Backend Tests / LFX Tests - Python 3.10
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
- GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
- GitHub Check: Test Starter Templates
- GitHub Check: test-starter-projects
🔇 Additional comments (44)
src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json (2)
635-635: Code hash updated to reflect ChatOutput session_id preservation changes.The code_hash has been updated (from cae45e2d53f6 to 8c87e536cca4) to reflect the functional changes in the ChatOutput component. This metadata field should uniquely identify the component code version.
709-709: Verify ChatOutput session_id preservation logic preserves incoming Message session_id correctly.The embedded ChatOutput code implements session_id preservation. Key implementation details to verify:
- Line context: The logic captures
existing_session_id = message.session_idwhenisinstance(self.input_value, Message) and not self.is_connected_to_chat_input()- Session resolution chain:
message.session_id = self.session_id or existing_session_id or (self.graph.session_id if hasattr(self, "graph") else None) or ""This prioritizes component-level session_id, then falls back to the incoming message's session_id, then graph-level, then empty string. Ensure this fallback order aligns with intended behavior for chat history tracking.
Can you confirm:
- The
is_connected_to_chat_input()method correctly identifies when ChatOutput is directly connected to a ChatInput component?- The fallback chain for session_id resolution doesn't inadvertently mask or override user-provided session IDs in edge cases?
src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json (1)
1734-1735: This review comment is incorrect.Message.textexplicitly acceptsIteratortype in addition tostrandAsyncIterator(seelfx/src/lfx/schema/message.pyline 38:text: str | AsyncIterator | Iterator | None). SinceGenerator[Any, None, None]is a subclass ofcollections.abc.Iterator, assigning a generator tomessage.textis type-safe and intentional. The suggested fix would break the streaming functionality that the type annotation was designed to support.Likely an incorrect or invalid review comment.
src/backend/base/langflow/initial_setup/starter_projects/Nvidia Remix.json (3)
514-514: Metadata hash update acknowledged.Code hash change only; no functional impact here.
589-589: Session ID preservation logic looks good.Precedence
self.session_id or existing_session_id or graph.session_id or ""is correct and fixes missing messages in chat.Please confirm:
is_connected_to_chat_input()reliably gates reuse across all starter flows.message.propertiesis always initialized; otherwise setmessage.properties = message.properties or Message.Properties()before assigningsource.
589-589: Review comment is technically incorrect and contradicts the project's established codebase patterns.The claim that
isinstance(x, Message | Data | ...)raises a TypeError at runtime is false. Python 3.10+ (which this project requires) fully supports PEP 604 union syntax inisinstance()calls. Moreover, the codebase already uses this pattern extensively throughout the project:
src/lfx/src/lfx/utils/util_strings.py:isinstance(data, dict | list)src/lfx/src/lfx/utils/data_structure.py:isinstance(value, list | tuple | set)src/lfx/src/lfx/serialization/serialization.py:isinstance(obj, int | float | bool | complex)src/lfx/src/lfx/schema/message.py:isinstance(value, AsyncIterator | Iterator)- And multiple other files
The code in the JSON file follows the project's established style. No changes are needed.
Likely an incorrect or invalid review comment.
src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json (3)
718-719: Good fix: session_id preservation logic is correct.Reusing incoming Message and falling back to component → existing_session_id → graph → "" avoids losing history context and prevents accidental storage when session_id is empty. Looks sound.
718-719: No defensive check needed for message.properties.The
Messageclass initializespropertiesviadefault_factory=Properties(src/lfx/src/lfx/schema/message.py line 51), guaranteeing it is never None. The code safely accessesmessage.properties.sourcewithout requiring defensive checks.Likely an incorrect or invalid review comment.
718-719: Generator handling is already covered by send_message().The
send_message()method in the parentChatComponentclass explicitly detects whenmessage.textis anIteratororAsyncIteratorand streams the content to convert it to a string before database storage (lines 1639-1643 in component.py). SinceGeneratoris a subtype ofIterator, this scenario is already handled correctly—no additional changes needed.Likely an incorrect or invalid review comment.
src/backend/base/langflow/initial_setup/starter_projects/Custom Component Generator.json (2)
2316-2317: LGTM: consistent session_id fallback across starters.Same preservation and fallback chain here. Consistency reduces hard-to-track chat display bugs.
2316-2317: The assignmentmessage.properties.source = self._build_source(...)is safe and requires no guarding. TheMessageclass initializespropertieswithField(default_factory=Properties)at the Pydantic model level, which guaranteespropertiesis always aPropertiesinstance. Similarly, thePropertiesclass initializessourcewithField(default_factory=Source), ensuring it is always aSourceinstance.Likely an incorrect or invalid review comment.
src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json (1)
1044-1119: Session_id preservation logic for ChatOutput is correctly implemented.The updated ChatOutput component now properly preserves incoming Message session_ids when reusing existing message objects. The capture of
existing_session_idbefore modifying message properties, combined with the fallback resolution chain (self.session_id or existing_session_id or graph.session_id or ""), ensures:
- Messages retain their original session context when passed through ChatOutput without an explicit session_id parameter.
- Component-level session_id takes priority (allowing explicit overrides).
- Graceful fallback to graph-level session_id and empty string prevents None values.
The code_hash update correctly reflects these behavioral changes. This aligns well with the PR objective of fixing ChatOutput message visibility in Playground chat.
src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json (2)
688-688: Code hash update notedHash reflects the ChatOutput logic change; no issues.
763-764: The project requires Python >=3.10 (as specified in pyproject.toml), and union syntax inisinstance()has been fully supported since Python 3.10. The code is correct as-is and does not need to be changed to tuple syntax. Using theA | B | Csyntax is idiomatic and appropriate for the project's minimum supported Python version.Likely an incorrect or invalid review comment.
src/backend/base/langflow/initial_setup/starter_projects/Search agent.json (2)
570-570: Code hash update acknowledgedMatches the embedded ChatOutput changes.
645-646: Session_id preservation logic is correct; union types in isinstance() are supportedThe
existing_session_idfallback path correctly prevents losing the original session. The union type syntax inisinstance()is fully compatible with the project's Python 3.10+ requirement, so no changes are needed for the isinstance checks.src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json (2)
426-426: Code hash updatedConsistent with ChatOutput behavior change; OK.
500-501: Good: session_id preservation logic aligns with PR objective.The existing code correctly preserves session_id from incoming messages without clobbering existing values, which is appropriate for the feature.
The suggested refactor to convert
isinstanceunions from|operator to tuples is unnecessary. The project targets Python 3.10+ (configured in pyproject.toml withrequires-python = ">=3.10,<3.14"), where the|operator for type unions is fully supported and part of PEP 604. Additionally, the codebase consistently uses this modern syntax throughout the main source code (visible incomponent_tool.py,mcp/util.py,agents/context.py, etc.). Converting to tuple syntax would create inconsistency with established project patterns.The code is correct as written.
src/backend/base/langflow/initial_setup/starter_projects/Hybrid Search RAG.json (2)
728-728: Code hash update acknowledged.No action needed.
803-804: Session continuity fix looks good; add small hardening and typing tweaks.
- Keep: existing_session_id fallback and graph/session_id resolution are correct for restoring ChatOutput visibility.
- Type: _build_source(source: str | None) inspects attributes (model_name/model). Widen to Any to reflect actual usage and avoid static/type-check noise.
- Safety: message.properties may be None depending on Message defaults. Guard before assignment.
- Streaming: convert_to_string can return a Generator, which is assigned to message.text. Confirm that Message/text and the Playground renderer support generators; otherwise wrap with a streaming-aware pathway or coerce to str.
Suggested diff:
- def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source: + def _build_source(self, id_: str | None, display_name: str | None, source: object | None) -> Source: @@ - message.properties.source = self._build_source(source_id, display_name, source) + # Ensure properties exists + if getattr(message, "properties", None) is None: + message.properties = type(message).Properties() # or Source container per Message schema + message.properties.source = self._build_source(source_id, display_name, source)And please verify generator handling:
If Message.text must be a string, replace generator assignment with a streaming send path or materialize the generator safely.
src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json (1)
153-153: Code hash update acknowledged.No action needed.
src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json (1)
1644-1644: ✓ ChatOutput session_id preservation logic looks correct.The updated ChatOutput component properly preserves session_id from reused Message objects. The fallback order (component/session self.session_id → existing_session_id → graph.session_id → "") ensures backward compatibility while fixing the chat persistence issue.
Key strengths:
- Correctly identifies the Message-reuse path with
not self.is_connected_to_chat_input()- Extracts and preserves existing_session_id before overwriting message properties
- Includes safe hasattr checks for the graph object
- Maintains an empty string default to prevent None issues
This should resolve the issue where ChatOutput messages weren't appearing in the Playground chat interface.
Also applies to: 1720-1761
src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json (3)
4129-4129: No action needed for code_hash update.Metadata-only change; safe to ignore.
4190-4210: Good fix: session_id preservation in ChatOutput.Reusing the incoming Message when possible and falling back to component/graph session_id prevents message loss in the Playground. This aligns with the PR objective.
Please confirm Message.properties is always initialized so that
message.properties.source = ...cannot raise.
4190-4210: Confirm ChatInput connection behavior.When connected directly to ChatInput, you don’t reuse the incoming Message. That’s likely intentional to avoid mutating stored messages. Please confirm this still preserves the original ChatInput session_id in cases where
self.session_idis empty by relying onself.graph.session_id.src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json (2)
565-565: Metadata update looks good.code_hash refresh aligns with the embedded ChatOutput changes.
639-739: Python version requirement already enforces 3.10+ support.The project's
pyproject.tomlspecifiesrequires-python = ">=3.10,<3.14", which fully supports PEP 604 union syntax inisinstance(). The code is correctly configured for the minimum Python version.src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json (1)
395-395: Metadata update looks good.code_hash matches the embedded ChatOutput changes.
src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json (1)
308-308: Metadata update looks good.code_hash reflects ChatOutput changes.
src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json (3)
501-501: No review needed for code_hash update.Hash change reflects code edits only.
575-575: Session continuity fix looks good.Preserving an existing Message.session_id with fallback to component → graph → "" is correct and should restore message display in the Playground as intended.
575-575: Guard against missing message.properties before setting source.message.properties.source is assigned unconditionally. If properties can be None for new Message(text=...), this will raise. Ensure properties exists or set via a safe setter.
+ if getattr(message, "properties", None) is None: + # initialize properties if your Message model supports it + message.properties = type(message).properties.__class__() # or a proper factory/constructor message.properties.source = self._build_source(source_id, display_name, source)If Message always initializes properties, disregard.
src/backend/base/langflow/initial_setup/starter_projects/Market Research.json (1)
553-553: Session continuity fix in ChatOutput looks good.Reusing incoming Message and preserving session_id when not wired to ChatInput is correct and should restore chat display behavior. Nice guard with is_connected_to_chat_input().
src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json (1)
448-448: Session continuity fix in ChatOutput is correct.Preserving an incoming Message's session_id (when not fed from ChatInput) should resolve missing messages in chat UI.
src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json (1)
642-718: ChatOutput session_id preservation and source handling look correctThe updated
message_responsecorrectly:
- Reuses an incoming
Messageonly when not connected toChatInput.- Preserves an existing
session_idand falls back to the component or graphsession_id.- Populates
properties.sourcevia_build_sourcewithout making unsafe assumptions about thesourceobject.
The validation andconvert_to_stringlogic are consistent with the accepted input types, and conditional storing based onmessage.session_idavoids unnecessary history writes.Also applies to: 921-997, 1200-1276
src/lfx/tests/unit/schema/test_schema_message.py (1)
81-99: Tests correctly updated forimage_urlmultimodal contentThe assertions in
test_message_with_single_imageandtest_message_with_multiple_imagesnow validate:
type == "image_url"for image blocks, and- presence and basic shape of
image_url["url"](starts with"data:image/"),which matches the new multimodal image representation and exercises real file handling via the cache. Test structure, naming, and fixtures remain clear and behavior-focused.
Also applies to: 104-133
src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json (1)
511-585: ChatOutput session_id preservation and input validation look correctThe updated
ChatOutputimplementation correctly:
- Reuses an incoming
Messageonly when not connected to a chat input, avoiding duplicate history writes.- Preserves an existing
session_idwhen present, while still allowing an explicitsession_idoverride and falling back tograph.session_idor"".- Validates
input_valuetypes defensively before conversion and only stores messages when a non-emptysession_idis available.This aligns with the stated goal of keeping Playground chat threading intact while remaining backward compatible with other usages.
src/lfx/tests/unit/schema/test_schema_data.py (1)
44-47: Image content assertions correctly updated toimage_urlstructureThe tests now assert the OpenAI-style image payload shape:
type == "image_url"- presence of
"image_url"and nested"url"urlstarting with the expected"data:image/png;base64,"prefix for both single and multiple images.This matches the standardized
{"type": "image_url", "image_url": {"url": "data:mime_type;base64,..."}}format and gives good coverage without over-specifying the full data URL.Based on learnings, this matches the expected OpenAI image_url format.
Also applies to: 74-82
src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json (1)
419-495: Consistent ChatOutput behavior and session_id handling across starter projectsThis starter’s
ChatOutputblock matches the updated implementation used elsewhere:
- Reuses incoming
Messageobjects when appropriate and preserves theirsession_id.- Resolves
session_idin the order: explicit component value → existing message → graph session → empty string.- Only persists to history when a
session_idis set.The consistency here should ensure Agent replies for this flow also render correctly in the Playground chat history.
src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json (1)
974-1050: ChatOutput session_id handling and embedded code are consistent and correctThe updated
ChatOutputsnippet correctly preserves an incomingMessage’ssession_idwhen reusing it and otherwise falls back to component or graphsession_id, matching the core implementation. This should fix missing messages in the Playground without changing public behavior elsewhere.src/backend/base/langflow/initial_setup/starter_projects/Knowledge Retrieval.json (1)
235-310: Aligned ChatOutput behavior with core implementationThe
ChatOutputcomponent here now uses the samemessage_responselogic as the core class, includingexisting_session_idcapture and thesession_idprecedence chain (component → existing message → graph →""). This keeps session continuity in the Knowledge Retrieval flow while remaining backward compatible.src/lfx/src/lfx/components/input_output/chat_output.py (1)
120-137: Session ID resolution fix inmessage_responseis soundCapturing
existing_session_idwhen reusing an incomingMessageand then resolvingmessage.session_idas:self.session_id or existing_session_id or (self.graph.session_id if hasattr(self, "graph") else None) or ""correctly:
- Lets an explicit component
session_idoverride everything,- Falls back to the reused message’s existing
session_idwhen present,- Then to the graph’s
session_id,- And finally to
""as a safe default.This directly addresses the session continuity bug in Playground chat without introducing new failure modes, and the
hasattr(self, "graph")guard keeps it safe when no graph is attached.src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json (1)
587-587: ChatOutput session_id preservation and reuse logic looks solidThe updated
ChatOutputimplementation correctly:
- Reuses an incoming
Messageonly when not connected to a chat input, avoiding mutation of live chat-input messages.- Preserves an existing
session_idfrom that message while still allowing an explicit componentsession_id(or graphsession_id) to override it via the precedence
component session_id → existing_session_id → graph.session_id → "".- Leaves storage behavior gated on a non-empty
message.session_id, which aligns with the session-preservation goal.No issues spotted; this should address the Playground chat visibility problems without regressions.
Also applies to: 661-661
src/lfx/src/lfx/base/agents/agent.py (1)
184-187: Multimodal input handling and defensiveinput_dictinit appear correctThe new logic in
run_agent:
- Guarantees
input_dict["input"]is always present before passing it into theRunnable(defensive block at Lines 184–187), which is safe even if currently redundant.- Correctly supports both legacy
"image"and standard"image_url"items inlc_message.content, extracting:
- Text segments into a single string
input_dict["input"].- Image segments into
HumanMessageentries appended tochat_history, preserving multimodal context without feeding non-text payload into the stringinput.- Maintains the final non-empty-input safeguard, so Anthropic-like providers won’t see an empty prompt even for image-only messages.
Behavior looks consistent with LangChain’s multimodal expectations and should fix Gemini/Anthropic image flows, assuming
lc_message.contentis always a list of dict-like items with"type"keys.Please sanity-check this against your current LangChain / provider stack (Anthropic, Gemini) to confirm that:
HumanMessage(content=[{"type": "image_url", ...}])is the expected format, and- Agents consuming
{"input": <str>, "chat_history": List[BaseMessage]}correctly propagate both text and images.Also applies to: 201-227
| "value": "from collections.abc import Generator\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom lfx.base.io.chat import ChatComponent\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, DropdownInput, HandleInput, MessageTextInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.schema.properties import Source\nfrom lfx.template.field.base import Output\nfrom lfx.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n documentation: str = \"https://docs.langflow.org/chat-input-and-output\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Inputs\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\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=\"context_id\",\n display_name=\"Context ID\",\n info=\"The context ID of the chat. Adds an extra layer to the local memory.\",\n value=\"\",\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 BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n advanced=True,\n info=\"Whether to clean data before converting to string.\",\n ),\n ]\n outputs = [\n Output(\n display_name=\"Output 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 # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n\n # Get source properties\n source, _, display_name, source_id = self.get_properties_from_source_component()\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message) and not self.is_connected_to_chat_input():\n message = self.input_value\n # Update message properties\n message.text = text\n # Preserve existing session_id from the incoming message if it exists\n existing_session_id = message.session_id\n else:\n message = Message(text=text)\n existing_session_id = None\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n # Preserve session_id from incoming message, or use component/graph session_id\n message.session_id = (\n self.session_id or existing_session_id or (self.graph.session_id if hasattr(self, \"graph\") else None) or \"\"\n )\n message.context_id = self.context_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n\n # Store message if needed\n if message.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _serialize_data(self, data: Data) -> str:\n \"\"\"Serialize Data object to JSON string.\"\"\"\n # Convert data.data to JSON-serializable format\n serializable_data = jsonable_encoder(data.data)\n # Serialize with orjson, enabling pretty printing with indentation\n json_bytes = orjson.dumps(serializable_data, option=orjson.OPT_INDENT_2)\n # Convert bytes to string and wrap in Markdown code blocks\n return \"```json\\n\" + json_bytes.decode(\"utf-8\") + \"\\n```\"\n\n def _validate_input(self) -> None:\n \"\"\"Validate the input data and raise ValueError if invalid.\"\"\"\n if self.input_value is None:\n msg = \"Input data cannot be None\"\n raise ValueError(msg)\n if isinstance(self.input_value, list) and not all(\n isinstance(item, Message | Data | DataFrame | str) for item in self.input_value\n ):\n invalid_types = [\n type(item).__name__\n for item in self.input_value\n if not isinstance(item, Message | Data | DataFrame | str)\n ]\n msg = f\"Expected Data or DataFrame or Message or str, got {invalid_types}\"\n raise TypeError(msg)\n if not isinstance(\n self.input_value,\n Message | Data | DataFrame | str | list | Generator | type(None),\n ):\n type_name = type(self.input_value).__name__\n msg = f\"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}\"\n raise TypeError(msg)\n\n def convert_to_string(self) -> str | Generator[Any, None, None]:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n self._validate_input()\n if isinstance(self.input_value, list):\n clean_data: bool = getattr(self, \"clean_data\", False)\n return \"\\n\".join([safe_convert(item, clean_data=clean_data) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return safe_convert(self.input_value)\n" | ||
| }, |
There was a problem hiding this comment.
Fix invalid isinstance() usage with union types (runtime TypeError).
_in ChatOutput.validate_input inside template.code value: using isinstance(x, Message | Data | ...) will raise TypeError: isinstance() arg 2 must be a type or tuple of types. Replace PEP 604 unions with a tuple.
- if isinstance(self.input_value, list) and not all(
- isinstance(item, Message | Data | DataFrame | str) for item in self.input_value
- ):
+ if isinstance(self.input_value, list) and not all(
+ isinstance(item, (Message, Data, DataFrame, str)) for item in self.input_value
+ ):
@@
- if not isinstance(
- self.input_value,
- Message | Data | DataFrame | str | list | Generator | type(None),
- ):
+ if not isinstance(
+ self.input_value,
+ (Message, Data, DataFrame, str, list, Generator, type(None)),
+ ):📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "value": "from collections.abc import Generator\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom lfx.base.io.chat import ChatComponent\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, DropdownInput, HandleInput, MessageTextInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.schema.properties import Source\nfrom lfx.template.field.base import Output\nfrom lfx.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n documentation: str = \"https://docs.langflow.org/chat-input-and-output\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Inputs\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\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=\"context_id\",\n display_name=\"Context ID\",\n info=\"The context ID of the chat. Adds an extra layer to the local memory.\",\n value=\"\",\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 BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n advanced=True,\n info=\"Whether to clean data before converting to string.\",\n ),\n ]\n outputs = [\n Output(\n display_name=\"Output 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 # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n\n # Get source properties\n source, _, display_name, source_id = self.get_properties_from_source_component()\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message) and not self.is_connected_to_chat_input():\n message = self.input_value\n # Update message properties\n message.text = text\n # Preserve existing session_id from the incoming message if it exists\n existing_session_id = message.session_id\n else:\n message = Message(text=text)\n existing_session_id = None\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n # Preserve session_id from incoming message, or use component/graph session_id\n message.session_id = (\n self.session_id or existing_session_id or (self.graph.session_id if hasattr(self, \"graph\") else None) or \"\"\n )\n message.context_id = self.context_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n\n # Store message if needed\n if message.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _serialize_data(self, data: Data) -> str:\n \"\"\"Serialize Data object to JSON string.\"\"\"\n # Convert data.data to JSON-serializable format\n serializable_data = jsonable_encoder(data.data)\n # Serialize with orjson, enabling pretty printing with indentation\n json_bytes = orjson.dumps(serializable_data, option=orjson.OPT_INDENT_2)\n # Convert bytes to string and wrap in Markdown code blocks\n return \"```json\\n\" + json_bytes.decode(\"utf-8\") + \"\\n```\"\n\n def _validate_input(self) -> None:\n \"\"\"Validate the input data and raise ValueError if invalid.\"\"\"\n if self.input_value is None:\n msg = \"Input data cannot be None\"\n raise ValueError(msg)\n if isinstance(self.input_value, list) and not all(\n isinstance(item, Message | Data | DataFrame | str) for item in self.input_value\n ):\n invalid_types = [\n type(item).__name__\n for item in self.input_value\n if not isinstance(item, Message | Data | DataFrame | str)\n ]\n msg = f\"Expected Data or DataFrame or Message or str, got {invalid_types}\"\n raise TypeError(msg)\n if not isinstance(\n self.input_value,\n Message | Data | DataFrame | str | list | Generator | type(None),\n ):\n type_name = type(self.input_value).__name__\n msg = f\"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}\"\n raise TypeError(msg)\n\n def convert_to_string(self) -> str | Generator[Any, None, None]:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n self._validate_input()\n if isinstance(self.input_value, list):\n clean_data: bool = getattr(self, \"clean_data\", False)\n return \"\\n\".join([safe_convert(item, clean_data=clean_data) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return safe_convert(self.input_value)\n" | |
| }, | |
| "value": "from collections.abc import Generator\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom lfx.base.io.chat import ChatComponent\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, DropdownInput, HandleInput, MessageTextInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.schema.properties import Source\nfrom lfx.template.field.base import Output\nfrom lfx.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n documentation: str = \"https://docs.langflow.org/chat-input-and-output\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Inputs\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\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=\"context_id\",\n display_name=\"Context ID\",\n info=\"The context ID of the chat. Adds an extra layer to the local memory.\",\n value=\"\",\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 BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n advanced=True,\n info=\"Whether to clean data before converting to string.\",\n ),\n ]\n outputs = [\n Output(\n display_name=\"Output 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 # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n\n # Get source properties\n source, _, display_name, source_id = self.get_properties_from_source_component()\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message) and not self.is_connected_to_chat_input():\n message = self.input_value\n # Update message properties\n message.text = text\n # Preserve existing session_id from the incoming message if it exists\n existing_session_id = message.session_id\n else:\n message = Message(text=text)\n existing_session_id = None\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n # Preserve session_id from incoming message, or use component/graph session_id\n message.session_id = (\n self.session_id or existing_session_id or (self.graph.session_id if hasattr(self, \"graph\") else None) or \"\"\n )\n message.context_id = self.context_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n\n # Store message if needed\n if message.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _serialize_data(self, data: Data) -> str:\n \"\"\"Serialize Data object to JSON string.\"\"\"\n # Convert data.data to JSON-serializable format\n serializable_data = jsonable_encoder(data.data)\n # Serialize with orjson, enabling pretty printing with indentation\n json_bytes = orjson.dumps(serializable_data, option=orjson.OPT_INDENT_2)\n # Convert bytes to string and wrap in Markdown code blocks\n return \" |
🤖 Prompt for AI Agents
In src/backend/base/langflow/initial_setup/starter_projects/Research Translation
Loop.json around lines 480 to 481, the code uses PEP 604 union syntax inside
isinstance() (e.g. isinstance(x, Message | Data | ...)), which raises a runtime
TypeError; replace all such isinstance checks with a tuple of types (e.g.
isinstance(x, (Message, Data, ...))) and similarly update any isinstance calls
that include Generator or type(None) to use tuples; ensure both validation
checks and list comprehensions use the tuple form so isinstance receives a type
or tuple of types.
🧩 Analysis chain
🏁 Script executed:
# First, let's find the Message class definition
rg -n "class Message" --type py -A 5Repository: langflow-ai/langflow
Length of output: 7612
🏁 Script executed:
# Search for Message.text field definition or type annotation
rg -n "text\s*:" --type py | grep -i message | head -20Repository: langflow-ai/langflow
Length of output: 1401
🏁 Script executed:
# Find the actual ChatOutput implementation in Python files (the JSON file only contains a string representation)
fd -e py -name "*chat*output*" -o -name "*output*"Repository: langflow-ai/langflow
Length of output: 294
🏁 Script executed:
# Search for Message class with text property
rg -n "class Message" -A 20 --type pyRepository: langflow-ai/langflow
Length of output: 21597
🏁 Script executed:
# Check if there are any validators on Message.text that might handle Generator
rg -A 20 "class Message\(Data\)" src/lfx/src/lfx/schema/message.py | head -40Repository: langflow-ai/langflow
Length of output: 1036
🏁 Script executed:
# Search for how Message.text is used when it contains iterators/generators
rg -B 3 -A 3 "message\.text" src/lfx/src/lfx/ --type py | head -50Repository: langflow-ai/langflow
Length of output: 4303
🏁 Script executed:
# Check if Generator is explicitly handled anywhere in the Message class or validators
rg -n "Generator" src/lfx/src/lfx/schema/message.pyRepository: langflow-ai/langflow
Length of output: 46
🏁 Script executed:
# Verify the type hierarchy - Generator should be a subclass of Iterator
python3 << 'EOF'
from typing import Generator, Iterator, AsyncIterator
from collections.abc import Generator as ABCGenerator
# Check class hierarchy
print("Generator is subclass of Iterator:", issubclass(ABCGenerator, Iterator))
print("Generator.__mro__:", ABCGenerator.__mro__)
EOFRepository: langflow-ai/langflow
Length of output: 150
🏁 Script executed:
# Let's check the actual convert_to_string() return type to be sure
rg -B 5 "def convert_to_string" src/lfx/src/lfx/base/io/chat.py -A 15Repository: langflow-ai/langflow
Length of output: 46
🏁 Script executed:
# Check the JSON file to see the actual convert_to_string implementation in the snippet
cat "src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json" | python3 << 'EOF'
import json
import sys
data = json.load(sys.stdin)
# Find ChatOutput in the structure
for key, value in data.items():
if isinstance(value, dict):
if "value" in value and "convert_to_string" in value["value"]:
print("Found convert_to_string in:", key)
# Extract and show the convert_to_string method
lines = value["value"].split('\n')
in_method = False
for i, line in enumerate(lines):
if 'def convert_to_string' in line:
in_method = True
if in_method:
print(line)
if 'return ' in line and in_method:
print(lines[i] if i < len(lines) else "")
EOFRepository: langflow-ai/langflow
Length of output: 784
Assign only str/AsyncIterator/Iterator to Message.text, not Generator.
convert_to_string() may return a Generator, but Message.text is typed as str | AsyncIterator | Iterator | None. The generator case must be materialized to a string before assignment.
async def message_response(self) -> Message:
# First convert the input to string if needed
- text = self.convert_to_string()
+ text = self.convert_to_string()
+ if isinstance(text, Generator):
+ # Materialize stream into a single string; consider streaming path if available
+ text = "".join(text)🤖 Prompt for AI Agents
In src/backend/base/langflow/initial_setup/starter_projects/Research Translation
Loop.json around lines 480-481, convert_to_string() can return a Generator but
Message.text must only be assigned str/AsyncIterator/Iterator/None; detect if
text is a Generator in message_response and materialize it to a string before
assigning to message.text (e.g., iterate the generator and join/concatenate its
yielded pieces into a single string, respecting clean_data conversion if
needed), then proceed with the rest of the message property assignments and
storage logic.
| "title_case": false, | ||
| "type": "code", | ||
| "value": "from collections.abc import Generator\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom lfx.base.io.chat import ChatComponent\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, DropdownInput, HandleInput, MessageTextInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.schema.properties import Source\nfrom lfx.template.field.base import Output\nfrom lfx.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n documentation: str = \"https://docs.langflow.org/chat-input-and-output\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Inputs\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\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=\"context_id\",\n display_name=\"Context ID\",\n info=\"The context ID of the chat. Adds an extra layer to the local memory.\",\n value=\"\",\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 BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n advanced=True,\n info=\"Whether to clean data before converting to string.\",\n ),\n ]\n outputs = [\n Output(\n display_name=\"Output 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 # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n\n # Get source properties\n source, _, display_name, source_id = self.get_properties_from_source_component()\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message) and not self.is_connected_to_chat_input():\n message = self.input_value\n # Update message properties\n message.text = text\n else:\n message = Message(text=text)\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id or self.graph.session_id or \"\"\n message.context_id = self.context_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n\n # Store message if needed\n if message.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _serialize_data(self, data: Data) -> str:\n \"\"\"Serialize Data object to JSON string.\"\"\"\n # Convert data.data to JSON-serializable format\n serializable_data = jsonable_encoder(data.data)\n # Serialize with orjson, enabling pretty printing with indentation\n json_bytes = orjson.dumps(serializable_data, option=orjson.OPT_INDENT_2)\n # Convert bytes to string and wrap in Markdown code blocks\n return \"```json\\n\" + json_bytes.decode(\"utf-8\") + \"\\n```\"\n\n def _validate_input(self) -> None:\n \"\"\"Validate the input data and raise ValueError if invalid.\"\"\"\n if self.input_value is None:\n msg = \"Input data cannot be None\"\n raise ValueError(msg)\n if isinstance(self.input_value, list) and not all(\n isinstance(item, Message | Data | DataFrame | str) for item in self.input_value\n ):\n invalid_types = [\n type(item).__name__\n for item in self.input_value\n if not isinstance(item, Message | Data | DataFrame | str)\n ]\n msg = f\"Expected Data or DataFrame or Message or str, got {invalid_types}\"\n raise TypeError(msg)\n if not isinstance(\n self.input_value,\n Message | Data | DataFrame | str | list | Generator | type(None),\n ):\n type_name = type(self.input_value).__name__\n msg = f\"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}\"\n raise TypeError(msg)\n\n def convert_to_string(self) -> str | Generator[Any, None, None]:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n self._validate_input()\n if isinstance(self.input_value, list):\n clean_data: bool = getattr(self, \"clean_data\", False)\n return \"\\n\".join([safe_convert(item, clean_data=clean_data) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return safe_convert(self.input_value)\n" | ||
| "value": "from collections.abc import Generator\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom lfx.base.io.chat import ChatComponent\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, DropdownInput, HandleInput, MessageTextInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.schema.properties import Source\nfrom lfx.template.field.base import Output\nfrom lfx.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n documentation: str = \"https://docs.langflow.org/chat-input-and-output\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Inputs\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\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=\"context_id\",\n display_name=\"Context ID\",\n info=\"The context ID of the chat. Adds an extra layer to the local memory.\",\n value=\"\",\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 BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n advanced=True,\n info=\"Whether to clean data before converting to string.\",\n ),\n ]\n outputs = [\n Output(\n display_name=\"Output 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 # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n\n # Get source properties\n source, _, display_name, source_id = self.get_properties_from_source_component()\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message) and not self.is_connected_to_chat_input():\n message = self.input_value\n # Update message properties\n message.text = text\n # Preserve existing session_id from the incoming message if it exists\n existing_session_id = message.session_id\n else:\n message = Message(text=text)\n existing_session_id = None\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n # Preserve session_id from incoming message, or use component/graph session_id\n message.session_id = (\n self.session_id or existing_session_id or (self.graph.session_id if hasattr(self, \"graph\") else None) or \"\"\n )\n message.context_id = self.context_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n\n # Store message if needed\n if message.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _serialize_data(self, data: Data) -> str:\n \"\"\"Serialize Data object to JSON string.\"\"\"\n # Convert data.data to JSON-serializable format\n serializable_data = jsonable_encoder(data.data)\n # Serialize with orjson, enabling pretty printing with indentation\n json_bytes = orjson.dumps(serializable_data, option=orjson.OPT_INDENT_2)\n # Convert bytes to string and wrap in Markdown code blocks\n return \"```json\\n\" + json_bytes.decode(\"utf-8\") + \"\\n```\"\n\n def _validate_input(self) -> None:\n \"\"\"Validate the input data and raise ValueError if invalid.\"\"\"\n if self.input_value is None:\n msg = \"Input data cannot be None\"\n raise ValueError(msg)\n if isinstance(self.input_value, list) and not all(\n isinstance(item, Message | Data | DataFrame | str) for item in self.input_value\n ):\n invalid_types = [\n type(item).__name__\n for item in self.input_value\n if not isinstance(item, Message | Data | DataFrame | str)\n ]\n msg = f\"Expected Data or DataFrame or Message or str, got {invalid_types}\"\n raise TypeError(msg)\n if not isinstance(\n self.input_value,\n Message | Data | DataFrame | str | list | Generator | type(None),\n ):\n type_name = type(self.input_value).__name__\n msg = f\"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}\"\n raise TypeError(msg)\n\n def convert_to_string(self) -> str | Generator[Any, None, None]:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n self._validate_input()\n if isinstance(self.input_value, list):\n clean_data: bool = getattr(self, \"clean_data\", False)\n return \"\\n\".join([safe_convert(item, clean_data=clean_data) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return safe_convert(self.input_value)\n" |
There was a problem hiding this comment.
Replace isinstance calls using PEP 604 union syntax (A | B) with tuple syntax (A, B) for Python 3.10/3.11 compatibility.
The code contains multiple isinstance() calls using PEP 604 union types (A | B syntax). While this syntax was introduced in Python 3.10, isinstance() support for runtime union type checking has inconsistent behavior and can raise TypeError on Python 3.10–3.11 depending on the exact Python build and version. Using tuple syntax (A, B) is the only reliable approach across all Python 3.10+ versions and is the recommended practice for isinstance/issubclass checks.
Update the following isinstance calls in ChatOutput._validate_input():
- if isinstance(self.input_value, list) and not all(
- isinstance(item, Message | Data | DataFrame | str) for item in self.input_value
- ):
+ if isinstance(self.input_value, list) and not all(
+ isinstance(item, (Message, Data, DataFrame, str)) for item in self.input_value
+ ):
invalid_types = [
type(item).__name__
for item in self.input_value
- if not isinstance(item, Message | Data | DataFrame | str)
+ if not isinstance(item, (Message, Data, DataFrame, str))
]
- if not isinstance(
- self.input_value,
- Message | Data | DataFrame | str | list | Generator | type(None),
- ):
+ if not isinstance(
+ self.input_value,
+ (Message, Data, DataFrame, str, list, Generator, type(None)),
+ ):
type_name = type(self.input_value).__name__🤖 Prompt for AI Agents
In src/backend/base/langflow/initial_setup/starter_projects/Travel Planning
Agents.json around line 575, replace the isinstance() calls that use PEP 604
union syntax with tuple syntax: change isinstance(item, Message | Data |
DataFrame | str) to isinstance(item, (Message, Data, DataFrame, str)) inside the
all(...) check, and change isinstance(self.input_value, Message | Data |
DataFrame | str | list | Generator | type(None)) to isinstance(self.input_value,
(Message, Data, DataFrame, str, list, Generator, type(None))); leave single-type
isinstance checks (e.g., Generator) unchanged.
| "value": "from collections.abc import Generator\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom lfx.base.io.chat import ChatComponent\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, DropdownInput, HandleInput, MessageTextInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.schema.properties import Source\nfrom lfx.template.field.base import Output\nfrom lfx.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n documentation: str = \"https://docs.langflow.org/chat-input-and-output\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Inputs\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\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=\"context_id\",\n display_name=\"Context ID\",\n info=\"The context ID of the chat. Adds an extra layer to the local memory.\",\n value=\"\",\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 BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n advanced=True,\n info=\"Whether to clean data before converting to string.\",\n ),\n ]\n outputs = [\n Output(\n display_name=\"Output 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 # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n\n # Get source properties\n source, _, display_name, source_id = self.get_properties_from_source_component()\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message) and not self.is_connected_to_chat_input():\n message = self.input_value\n # Update message properties\n message.text = text\n # Preserve existing session_id from the incoming message if it exists\n existing_session_id = message.session_id\n else:\n message = Message(text=text)\n existing_session_id = None\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n # Preserve session_id from incoming message, or use component/graph session_id\n message.session_id = (\n self.session_id or existing_session_id or (self.graph.session_id if hasattr(self, \"graph\") else None) or \"\"\n )\n message.context_id = self.context_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n\n # Store message if needed\n if message.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _serialize_data(self, data: Data) -> str:\n \"\"\"Serialize Data object to JSON string.\"\"\"\n # Convert data.data to JSON-serializable format\n serializable_data = jsonable_encoder(data.data)\n # Serialize with orjson, enabling pretty printing with indentation\n json_bytes = orjson.dumps(serializable_data, option=orjson.OPT_INDENT_2)\n # Convert bytes to string and wrap in Markdown code blocks\n return \"```json\\n\" + json_bytes.decode(\"utf-8\") + \"\\n```\"\n\n def _validate_input(self) -> None:\n \"\"\"Validate the input data and raise ValueError if invalid.\"\"\"\n if self.input_value is None:\n msg = \"Input data cannot be None\"\n raise ValueError(msg)\n if isinstance(self.input_value, list) and not all(\n isinstance(item, Message | Data | DataFrame | str) for item in self.input_value\n ):\n invalid_types = [\n type(item).__name__\n for item in self.input_value\n if not isinstance(item, Message | Data | DataFrame | str)\n ]\n msg = f\"Expected Data or DataFrame or Message or str, got {invalid_types}\"\n raise TypeError(msg)\n if not isinstance(\n self.input_value,\n Message | Data | DataFrame | str | list | Generator | type(None),\n ):\n type_name = type(self.input_value).__name__\n msg = f\"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}\"\n raise TypeError(msg)\n\n def convert_to_string(self) -> str | Generator[Any, None, None]:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n self._validate_input()\n if isinstance(self.input_value, list):\n clean_data: bool = getattr(self, \"clean_data\", False)\n return \"\\n\".join([safe_convert(item, clean_data=clean_data) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return safe_convert(self.input_value)\n" | ||
| }, |
There was a problem hiding this comment.
Fix invalid isinstance() usage with union types (runtime TypeError).
_in ChatOutput.validate_input inside template.code value: replace union types in isinstance with a tuple to avoid runtime TypeError.
- if isinstance(self.input_value, list) and not all(
- isinstance(item, Message | Data | DataFrame | str) for item in self.input_value
- ):
+ if isinstance(self.input_value, list) and not all(
+ isinstance(item, (Message, Data, DataFrame, str)) for item in self.input_value
+ ):
@@
- if not isinstance(
- self.input_value,
- Message | Data | DataFrame | str | list | Generator | type(None),
- ):
+ if not isinstance(
+ self.input_value,
+ (Message, Data, DataFrame, str, list, Generator, type(None)),
+ ):📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "value": "from collections.abc import Generator\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom lfx.base.io.chat import ChatComponent\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, DropdownInput, HandleInput, MessageTextInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.schema.properties import Source\nfrom lfx.template.field.base import Output\nfrom lfx.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n documentation: str = \"https://docs.langflow.org/chat-input-and-output\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Inputs\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\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=\"context_id\",\n display_name=\"Context ID\",\n info=\"The context ID of the chat. Adds an extra layer to the local memory.\",\n value=\"\",\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 BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n advanced=True,\n info=\"Whether to clean data before converting to string.\",\n ),\n ]\n outputs = [\n Output(\n display_name=\"Output 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 # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n\n # Get source properties\n source, _, display_name, source_id = self.get_properties_from_source_component()\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message) and not self.is_connected_to_chat_input():\n message = self.input_value\n # Update message properties\n message.text = text\n # Preserve existing session_id from the incoming message if it exists\n existing_session_id = message.session_id\n else:\n message = Message(text=text)\n existing_session_id = None\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n # Preserve session_id from incoming message, or use component/graph session_id\n message.session_id = (\n self.session_id or existing_session_id or (self.graph.session_id if hasattr(self, \"graph\") else None) or \"\"\n )\n message.context_id = self.context_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n\n # Store message if needed\n if message.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _serialize_data(self, data: Data) -> str:\n \"\"\"Serialize Data object to JSON string.\"\"\"\n # Convert data.data to JSON-serializable format\n serializable_data = jsonable_encoder(data.data)\n # Serialize with orjson, enabling pretty printing with indentation\n json_bytes = orjson.dumps(serializable_data, option=orjson.OPT_INDENT_2)\n # Convert bytes to string and wrap in Markdown code blocks\n return \"```json\\n\" + json_bytes.decode(\"utf-8\") + \"\\n```\"\n\n def _validate_input(self) -> None:\n \"\"\"Validate the input data and raise ValueError if invalid.\"\"\"\n if self.input_value is None:\n msg = \"Input data cannot be None\"\n raise ValueError(msg)\n if isinstance(self.input_value, list) and not all(\n isinstance(item, Message | Data | DataFrame | str) for item in self.input_value\n ):\n invalid_types = [\n type(item).__name__\n for item in self.input_value\n if not isinstance(item, Message | Data | DataFrame | str)\n ]\n msg = f\"Expected Data or DataFrame or Message or str, got {invalid_types}\"\n raise TypeError(msg)\n if not isinstance(\n self.input_value,\n Message | Data | DataFrame | str | list | Generator | type(None),\n ):\n type_name = type(self.input_value).__name__\n msg = f\"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}\"\n raise TypeError(msg)\n\n def convert_to_string(self) -> str | Generator[Any, None, None]:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n self._validate_input()\n if isinstance(self.input_value, list):\n clean_data: bool = getattr(self, \"clean_data\", False)\n return \"\\n\".join([safe_convert(item, clean_data=clean_data) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return safe_convert(self.input_value)\n" | |
| }, | |
| def _validate_input(self) -> None: | |
| """Validate the input data and raise ValueError if invalid.""" | |
| if self.input_value is None: | |
| msg = "Input data cannot be None" | |
| raise ValueError(msg) | |
| if isinstance(self.input_value, list) and not all( | |
| isinstance(item, (Message, Data, DataFrame, str)) for item in self.input_value | |
| ): | |
| invalid_types = [ | |
| type(item).__name__ | |
| for item in self.input_value | |
| if not isinstance(item, (Message, Data, DataFrame, str)) | |
| ] | |
| msg = f"Expected Data or DataFrame or Message or str, got {invalid_types}" | |
| raise TypeError(msg) | |
| if not isinstance( | |
| self.input_value, | |
| (Message, Data, DataFrame, str, list, Generator, type(None)), | |
| ): | |
| type_name = type(self.input_value).__name__ | |
| msg = f"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}" | |
| raise TypeError(msg) |
🤖 Prompt for AI Agents
src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json
around lines 1734-1735: the code uses PEP 604 union types (e.g., Message | Data
| DataFrame | str and Generator | type(None)) inside isinstance() which raises a
runtime TypeError; replace those union uses with tuples of types (e.g.,
(Message, Data, DataFrame, str) and (Generator, type(None))) wherever they
appear in _validate_input (both in the list-membership check and the final
isinstance check) so isinstance receives a tuple of types instead of a union
expression.
…://github.com/langflow-ai/langflow into fix/image-upload-gemini-anthropic-chat-output
…thropic-chat-output
…://github.com/langflow-ai/langflow into fix/image-upload-gemini-anthropic-chat-output
* Fix image upload for Gemini/Anthropic and ChatOutput session_id preservation * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix ruff erros * [autofix.ci] apply automated fixes * resolve conflicts * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * build component index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix: Image upload for Gemini/Anthropic (#10867) * Fix image upload for Gemini/Anthropic and ChatOutput session_id preservation * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix ruff erros * [autofix.ci] apply automated fixes * resolve conflicts * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * build component index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Himavarsha <40851462+HimavarshaVS@users.noreply.github.com>
* Fix image upload for Gemini/Anthropic and ChatOutput session_id preservation * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix ruff erros * [autofix.ci] apply automated fixes * resolve conflicts * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * build component index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* docs: update component links to individual pages (#10706) * Revert "Revert "docs: update component documentation links to individual pages"" This reverts commit 0bc27d6. * [autofix.ci] apply automated fixes * llm-selector-renamed * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Apply suggestions from code review * [autofix.ci] apply automated fixes * Apply suggestions from code review * [autofix.ci] apply automated fixes * rebuild-component-index * update-component-index * [autofix.ci] apply automated fixes * build-index * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: avoid updating Message if ChatOutput is connected to ChatInput (#10586) * fix: resolved merge conflict * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix: create a new message to avoid mutating shared instances * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix: resolved merge conflict * [autofix.ci] apply automated fixes * fix: resolved merge conflict * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix: added a check for using exisiting message object * fix: remove unwanted import * fix: resolve merge conflict * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix: add None checks to prevent errors * fix: resolve merge conflict * [autofix.ci] apply automated fixes * fix: backend unit test * fix: resolve merge conflict * [autofix.ci] apply automated fixes * fix: ruff styling errors * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Feat: Runflow optimization and improved dropdown behavior (#10720) * feat: optimize dropdown filtering and output resolution misc: remove commented out code feat: add refresh button and sort flows by updated_at date from most to least recent ruff (flow.py imports) improve fn contracts in runflow and improve flow id retrieval logic based on graph exec context add dynamic outputs and optimize db lookups add flow cache and db query for getting a single flow by id or name cache run outputs and add refresh context to build config misc misc use ids for flow retrieval misc fix missing flow_id bug add unit and integration tests add input field flag to persist hidden fields at runtime move unit tests and change input and output display names chore: update component index fix: fix tool mode when flow has multiple inputs by dynamically creating resolvers chore: update component index ruff (run_flow and tests) add resolvers to outputs map for non tool mode runtime fix tests (current flow excluded in db fetch) mypy (helpers/flow.py) chore: update component index remove unused code and clean up comments fix: persist user messages in chat-based flows via session injection chore: update component index empty string fallback for sessionid in chat.py chore: update component index chore: update component index cache invalidation with timestamps misc add cache invalidation chore: update component index chore: update comp idx ruff (run_flow.py) change session_id input type to MessageTextInput chore: update component index chore: update component index chore: update component index chore: update component index sync starter projects with main chore: update component index chore: update component index chore: update component index remove dead code + impl coderabbit suggestions chore: update component index chore: update component index clear options metadata before updating chore: update component index sync starter projects with main sync starter projects with main default param val (list flows) * chore: update component index * add integration tests * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: Cristhian Zanforlin <criszl@192.168.15.88> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Add dynamic tool mode descriptions for agent integration (#10744) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Add profile picture management and API endpoints (#10763) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * deps: upgrade altk (#10804) upgrade altk: * fix: use running event loop to fix asyncio error when calling mcp tools (#10806) * use existing event loop instead of recreating when calling mcp tools * component index * [autofix.ci] apply automated fixes * starter projects * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Improve file processing robustness and error feedback (#10781) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: resolve merge conflict (#10831) * fix: fixed warning on console for nested button (#10724) (#10832) * removed unnecessary buttons on the flows page * added the asChild prop and hid button so they are not accessible by tabbing * added tab index to ensure that buttons as not selectable using the tab * made sure that accessibility is possible one bulk selection is enabled * made sure that accessibility is possible one bulk selection is enabled * Fix: added testcases and refactor * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes --------- Co-authored-by: Olayinka Adelakun <olayinkaadelakun@Olayinkas-MacBook-Pro.local> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: fixed warning on console (#10745) (#10830) * remove console warnings * [autofix.ci] apply automated fixes --------- Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: mask value to hide null field being returned (#10778) (#10829) * fix: mask value to hide null field being returned * [autofix.ci] apply automated fixes * fix: added testcase and updated functionality --------- Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com> 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: Olayinka Adelakun <olayinkaadelakun@Olayinkas-MacBook-Pro.local> * Fix: Allow refresh list button to stay stagnant while zoom (Safari) (… (#10827) Fix: Allow refresh list button to stay stagnant while zoom (Safari) (#10777) * remove sticky as it was causing the refresh list to float on safari * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes --------- Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * feat: Add superuser support for running any user flow (#10808) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Revert "feat: Add superuser support for running any user flow (#10808)" This reverts commit 423419e. * fix: Ollama models list in Agent component (#10814) * fix: Ollama model list fails to load in Agent and Ollama components * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Fix: Ensure Default Tab is Credential (#10779) (#10826) * fix: made sure the tab is visible * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Fix: added typing * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix: added testcases * fix: added handleOnValue change function and created a helper file --------- Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Olayinka Adelakun <olayinkaadelakun@Olayinkas-MacBook-Pro.local> Co-authored-by: Carlos Coelho <80289056+carlosrcoelho@users.noreply.github.com> * chore: update cuga version (#10737) (#10738) Co-authored-by: Sami Marreed <sami.marreed@ibm.com> * chore: Remove DataFrameToToolsetComponent and related tests (#10845) Remove DataFrameToToolsetComponent and related tests Deleted the DataFrameToToolsetComponent implementation, its import/registration in the processing module, and all associated unit tests. This cleans up unused code and test files related to converting DataFrame rows into toolset actions. * fix: Handle GCP JSON parsing credentials (#10859) fix: Proper parsing of GCP credentials JSON (#10828) * fix: Proper parsing of GCP credentials JSON * Update save_file.py * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Update test_save_file_component.py * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Fix GCP issues * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Update test_save_file_component.py * Update save_file.py * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Update save_file.py * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Update save_file.py * Fix ruff errors * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: anthropic constants (#10862) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Add feature flag check to simplified_run_flow_session (#10863) * fix: Improve the debugging messages on startup (#10864) * fix: Suppress SIGSEGV errors on startup (#10849) * fix: Suppress SIGSEGV errors * Update test_cli.py * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Update News Aggregator.json Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Don't fail if doc column is missing (#10746) (#10872) * fix: Don't fail if doc column is missing * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Surface warning message to the UI * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Update test_docling_utils.py * [autofix.ci] apply automated fixes * Update test_docling_utils.py --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * add x-api-key auth option * fix(auth): Disallow refresh token access to API endpoints * fix: Properly support the Batch Run component for watsonX models (#10877) * fix: Support Batch Run with watsonX (#10848) * fix: Support Batch Run with watsonX * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Update batch_run.py * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Image upload for Gemini/Anthropic (#10880) * fix: Image upload for Gemini/Anthropic (#10867) * Fix image upload for Gemini/Anthropic and ChatOutput session_id preservation * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix ruff erros * [autofix.ci] apply automated fixes * resolve conflicts * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * build component index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Himavarsha <40851462+HimavarshaVS@users.noreply.github.com> * fix: Improve the default startup logging for readability (#10894) fix: Clean up the default startup logging (#10842) * fix: Clean up the default startup logging * [autofix.ci] apply automated fixes * Update manager.py * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Update test_security_cors.py * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Himavarsha <40851462+HimavarshaVS@users.noreply.github.com> * Fix: lfx serve aysncio event loop error (#10888) fix lfx serve asyncio event loop bug * fix: Update LangflowCounts component to format star and Discord counts (#10896) * fixed counts * fix: Update LangflowCounts component to format star and Discord counts --------- Co-authored-by: Deon Sanchez <69873175+deon-sanchez@users.noreply.github.com> * Fix: update lfx serve tests to mock the .serve() to prevent hanging (#10905) port lfx serve test fix from main * Fix: lfx run agent _noopresult not iterable error (#10893) * fix _noopresult not iterable and session.add never awaited error and warning, respectively * just make the add stub sync * Fix: lfx run agent _noopresult not iterable error (#10911) * fix _noopresult not iterable and session.add never awaited error and warning, respectively * just make the add stub sync * the real final solution v3 * real solution v4 * revert * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Add graceful subprocess cleanup during shutdown (#10906) * add mcp cleanup function * refactor(mcp_cleanup.py): simplify error handling using contextlib.suppress to improve code readability test(mcp_cleanup.py): update tests to use context manager for patching to enhance clarity and maintainability --------- Co-authored-by: Adam Aghili <Adam.Aghili@ibm.com> * fix(workflows): include src/lfx/uv.lock in git add command to ensure all necessary files are tracked fix(Makefile): add --no-sources flag to uv build command for langflow_base to optimize build process * chore(nightly_build.yml): remove unnecessary directory change for lfx in nightly build workflow to streamline the process * chore(release_nightly): update build command to include --no-sources flag for Langflow Base CLI to ensure proper build configuration fix(Makefile): remove --no-sources from build_langflow_base to align with updated build command in release workflow * chore(chat.py): remove unused future annotations import to clean up code * fix(chat.py): add future annotations import for better type hinting support fix(deps.py): move certain imports outside TYPE_CHECKING for FastAPI compatibility and update type hinting for get_cache_service function * chore: print version * chore: use release_tag as version * fix: --prerelease=allow * fix: correctly raise file not found errors in File GET endpoints (#10922) fix: correctly raise file not found errors in File GET endpoints (#10908) * Clean up the file GET endpoints * Add test * [autofix.ci] apply automated fixes * ruff/mypy * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Fix issues with async * use uvlock from main * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Hare <ericrhare@gmail.com> Co-authored-by: Himavarsha <40851462+HimavarshaVS@users.noreply.github.com> * fix: image pathing to operate with s3 storage (#10919) (#10929) * Fix image pathing to operate with s3 storage * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * add test * [autofix.ci] apply automated fixes * ruff * Add abstract method annotation * [autofix.ci] apply automated fixes * fix: use parse_file_path in get_files for S3 storage compatibility --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: himavarshagoutham <himavarshajan17@gmail.com> * Feat: migrate MCP transport from SSE to streamable http (#10934) * port #10727 * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * refactor(deps.py): reorganize imports for clarity and compliance with FastAPI requirements fix(deps.py): update return type of get_cache_service function to use Union for better type hinting * fix: update sidebar icon styles to maintain backward compatibility (#10948) * fix: Add empty input check in ALTKAgent for Anthropic (#10926) * fix: Add empty input check in ALTKAgent for Anthropic Shamelessly copies agent.py's empty input check to prevent Anthropic API errors. * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: Jason Tsay <jason.tsay@ibm.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: add condition to not make folder download fail when flow has Note component (#10953) * fix: Enhance error handling for langchain-core version compatibility (#10768) * fix: Restrict message and session access to flow owners (#10973) * feat(monitor.py): add user flow filtering to message sessions and messages endpoints to enhance data access control refactor(monitor.py): remove dependencies from route decorators and pass current_user as a parameter for better clarity and maintainability * test: update message-related test fixtures to associate messages with user-specific flows This change ensures that messages created in tests are linked to a flow specific to the active user, allowing for better filtering and organization of messages in the database. It enhances the test environment by simulating real-world usage scenarios more accurately. * chore(monitor.py): reorder import statements to follow consistent structure and improve readability * Fix: lfx run with agent component throws '_NoopResult' object is not iterable' (#10914) * fix _noopresult not iterable and session.add never awaited error and warning, respectively * just make the add stub sync * the real final solution v3 * real solution v4 * revert * fix noopresult not iterable error and add was not awaited warning * do await check in aupdate_messages * [autofix.ci] apply automated fixes --------- Co-authored-by: Himavarsha <40851462+HimavarshaVS@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Support tool mode for components that have no inputs (#10982) fix: Support tool mode in components without inputs (#10959) * fix: Support tool mode in components without inputs * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: (Cherry Pick) default Ollama base url (#10981) * fix: Properly set a default Ollama base url (#10940) * fix: Properly set a default Ollama base url * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Add authentication to various endpoints (#10977) (#10985) * fix: Add authentication to various endpoints (#10977) * fix: Add authentication to various endpoints * [autofix.ci] apply automated fixes * Couple more endpoints * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Update log_router.py * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Update mcp.py * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Fix ruff errors * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Update test_endpoints.py * Fix tests * Update Nvidia Remix.json * Update test_registration.py * [autofix.ci] apply automated fixes * Update test_files.py Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Address review comments Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Review updates Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Fix: ensure streamable-http session manager is entered and exited from the same task (#10991) * cherry pick #10966 * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Fix: cuga integration (#10976) (#10990) * Fix: cuga integration (#10976) * feat: upgrade cuga version * chore: add component index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix: cuga component * chore: update index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * fix: upgrade cuga * fix: new component index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * chore: add component index * [autofix.ci] apply automated fixes * chore: update package * chore: update index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix: cuga relatetive temp * fix: update cuga * chore: add component index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * fix: remove space * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes --------- Co-authored-by: Sami Marreed <sami.marreed@ibm.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * test(webhook): add comprehensive tests for webhook endpoint functionality and error handling (#10995) * fix: Improve image path extraction and validation (#10999) * fix: make key generated on mcp json be shown, make placeholder show up if key not generated (#10997) * changed api key to show placeholder when api key is empty * changed useMcpServer to use generated api key if store api key is empty, add dependency to callback * [autofix.ci] apply automated fixes * Added tests * [autofix.ci] apply automated fixes * Update src/frontend/src/pages/MainPage/pages/homePage/hooks/useMcpServer.ts Co-authored-by: Cristhian Zanforlin Lousa <cristhian.lousa@gmail.com> --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Cristhian Zanforlin Lousa <cristhian.lousa@gmail.com> * Fix: disable mcp sse endpoints astra (#11004) * disable mcp sse transport endpoints in astra cloud * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Himavarsha <40851462+HimavarshaVS@users.noreply.github.com> * fix: mcp-proxy process leak (#11008) * fix: mcp-proxy process leak (#10988) * fix leak * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Move MCP client imports out of loop iteration in get_servers (#10993) * Initial plan * Move MCPStdioClient and MCPStreamableHttpClient imports to get_servers function Co-authored-by: phact <1313220+phact@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: phact <1313220+phact@users.noreply.github.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Edwin Jose <edwin.jose@datastax.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: phact <1313220+phact@users.noreply.github.com> Co-authored-by: Adam Aghili <Adam.Aghili@ibm.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: Sebastián Estévez <estevezsebastian@gmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Edwin Jose <edwin.jose@datastax.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: phact <1313220+phact@users.noreply.github.com> * feat: add build-nightly-ep to docker-nightly-build (#10942) * feat: add build-nightly-ep to docker-nightly-build add build-nightly-ep to docker-nightly-build * chore: update where langflow-nightly-ep is used update where langflow-nightly-ep is used to match update where langflow-nightly-all * chore: add nightly-main-ep to release_nightly add nightly-main-ep to call_docker_build_main_ep in release_nightly * chore: run what is already here * chore: revert .secrets.baseline and let it regen * fix(message.py): simplify file presence check using kwargs.get() for better readability and maintainability * fix: Disable Local storage option in Write File component for cloud environments (#11003) (#11022) * fix: Disable Local storage option in Write File component for cloud environments (#11003) * modify savefile component * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * component index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Update src/lfx/src/lfx/components/files_and_knowledge/save_file.py Co-authored-by: Hamza Rashid <74062092+HzaRashid@users.noreply.github.com> * fix ruff errors * fix conflicts * resolve conflicts * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix indentation error * [autofix.ci] apply automated fixes * update options dynamically * build component index * [autofix.ci] apply automated fixes * fix ruff errors * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Hamza Rashid <74062092+HzaRashid@users.noreply.github.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Hamza Rashid <74062092+HzaRashid@users.noreply.github.com> * fix: cuga update (#11019) (#11026) * fix: update cuga version * chore: build index Co-authored-by: Sami Marreed <sami.marreed@ibm.com> * fix: langwatch traces all api endpoints (#11014) * create tracerprovider so langwatch doesnt pick up fastapi calls * move opentel sdk imports to the top * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Fix: improve exception handling and status code for disabled endpoints (#11012) * port #11011 * recover line from 1.7.0 * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix(deps): Pin langchain-mcp-adapters to resolve langchain-core compatibility (#11037) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Make sure the research translation loop template is properly operating (#11042) * fix: Make sure loop inputs are properly handled in research (#11029) * fix: Make sure loop inputs are properly handled in research Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes * Update reactflowUtils.ts Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Update reactflowUtils.ts Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Revert "Update reactflowUtils.ts" This reverts commit 9c8b1d1. * Revert "Update reactflowUtils.ts" This reverts commit 6be7ab9. * Fix template Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes * Update Research Translation Loop.json Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Update reactflowUtils.ts Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --------- Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * Update Research Translation Loop.json Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: disable knowledge components in astra (#11047) * cherry-pick #11046 * update component index * update component index again * fix: Advanced mode in read file component (#11041) (#11056) * fix: Advanced mode in read file component (#11041) * add a proper file path * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Update file.py Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * build component index * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * build component index * [autofix.ci] apply automated fixes * Fix incorrect use of .tempdir Co-Authored-By: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Hare <ericrhare@gmail.com> * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Hare <ericrhare@gmail.com> * fix: validate flow file_save path is in a valid location (#11060) fix: validate flow file_save path is in a valid location (#11039) * Validate flow file save path is in a valid location * clean up logic * fix tests * comments * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * fix backslash vuln * [autofix.ci] apply automated fixes * add storage service param to function in agentic utils * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Ruff errors * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * Resolve path in setup * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * comp index update * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Hare <ericrhare@gmail.com> * refactor: Move fetch credentials to the customizations (#11049) (#11063) move fetch credentials to the customizations * fix: Fix async context handling in serve command and add integration tests (#10776) * refactor(tests): rename test IDs from helpersCreate List and logicPass to processingCreate List and flow_controlsPass for consistency and clarity in decision flow tests * refactor: Langflow cloud updates (#10910) * refactor: Use customization to get api base urls (#10871) * fixed counts * use customization to get api base urls --------- Co-authored-by: Deon Sanchez <69873175+deon-sanchez@users.noreply.github.com> * refactor: add code sample customizations (#10884) * add code sample customizations * import cleanup * embedded widget generator --------- Co-authored-by: Deon Sanchez <69873175+deon-sanchez@users.noreply.github.com> * fix: release workflow (#11087) * chore(release.yml): update release_lfx input description and make it optional to improve clarity feat(release.yml): add ensure-lfx-published job to automate LFX version check and publishing process to PyPI * chore: clean up release workflow comment out unneeded cross platform test and move steps around to match the already existing pattern --------- Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> * Revert "fix: release workflow " (#11088) Revert "fix: release workflow (#11087)" This reverts commit b26d032. * fix: release workflow (#11089) * chore(release.yml): update release_lfx input description and make it optional to improve clarity feat(release.yml): add ensure-lfx-published job to automate LFX version check and publishing process to PyPI * chore: clean up release workflow comment out unneeded cross platform test and move steps around to match the already existing pattern * chore: remove test-lfx-cross-platform remove test-lfx-cross-platform * chore: address some of co-pilots comments address some of co-pilots comments --------- Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> * fix: use langflow package path for database location (#11107) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * chore: bump versions for langflow 1.7.1, langflow-base 0.7.1, and lfx 0.2.1 (#11108) * chore: update version to 0.2.1 in pyproject.toml * bump version to 1.7.1 in package.json * chore: bump version to 0.7.1 and update lfx dependency to 0.2.1 in pyproject.toml * chore: bump versions for langflow, langflow-base, and lfx in pyproject.toml and uv.lock * regenarate lock based on release branch * new package-lock fixed * fix: regenerate package-lock.json with missing nested dependencies Adds canvas@2.11.2 (for rehype-mathjax) and yaml@2.8.2 (for tailwindcss) that were missing from the lock file causing npm ci to fail. --------- Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> * test(regression): update test to use box selection for Combine Text nodes instead of Ctrl/Meta+click for better reliability in Playwright with ReactFlow * test(fileUploadComponent.spec.ts): increase timeout duration for file rename tests to ensure stability test(general-bugs-reset-flow-run.spec.ts): add wait time to improve reliability of component build checks * Template update * [autofix.ci] apply automated fixes * Fix test failures --------- Co-authored-by: Mendon Kissling <59585235+mendonk@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: keval shah <kevalvirat@gmail.com> Co-authored-by: Hamza Rashid <74062092+HzaRashid@users.noreply.github.com> Co-authored-by: Cristhian Zanforlin <criszl@192.168.15.88> Co-authored-by: Cristhian Zanforlin Lousa <cristhian.lousa@gmail.com> Co-authored-by: Jordan Frazier <122494242+jordanrfrazier@users.noreply.github.com> Co-authored-by: olayinkaadelakun <olayinka.adelakun@ibm.com> Co-authored-by: Olayinka Adelakun <olayinkaadelakun@Olayinkas-MacBook-Pro.local> Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com> Co-authored-by: Carlos Coelho <80289056+carlosrcoelho@users.noreply.github.com> Co-authored-by: Himavarsha <40851462+HimavarshaVS@users.noreply.github.com> Co-authored-by: Sami Marreed <sami.marreed@ibm.com> Co-authored-by: Edwin Jose <edwin.jose@datastax.com> Co-authored-by: Eric Hare <ericrhare@gmail.com> Co-authored-by: Mike Pawlowski <mpawlow@ca.ibm.com> Co-authored-by: Viktor Avelino <64113566+viktoravelino@users.noreply.github.com> Co-authored-by: Deon Sanchez <69873175+deon-sanchez@users.noreply.github.com> Co-authored-by: himavarshagoutham <himavarshajan17@gmail.com> Co-authored-by: Jason Tsay <jason.tsay@ibm.com> Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> Co-authored-by: Sebastián Estévez <estevezsebastian@gmail.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: phact <1313220+phact@users.noreply.github.com> Co-authored-by: Mike Fortman <michael.fortman@datastax.com>
Fix Image Upload for Gemini/Anthropic and ChatOutput Display
Issues Fixed
Changes
create_image_content_dictto return the correctimage_urlformat that Gemini and Anthropic expectimage(legacy) andimage_url(standard) typessession_idfrom incoming Message objects so messages appear in chatimage_urlformatTesting
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.