Skip to content

feat: add MiniMax provider support#12655

Open
octo-patch wants to merge 3 commits into
langflow-ai:mainfrom
octo-patch:feature/add-minimax-provider
Open

feat: add MiniMax provider support#12655
octo-patch wants to merge 3 commits into
langflow-ai:mainfrom
octo-patch:feature/add-minimax-provider

Conversation

@octo-patch
Copy link
Copy Markdown

@octo-patch octo-patch commented Apr 13, 2026

Summary

  • Add MiniMaxModelComponent with OpenAI-compatible API (https://api.minimax.io/v1)
  • Support MiniMax-M2.7 (default) and MiniMax-M2.7-highspeed models
  • Add MINIMAX_API_KEY environment variable support
  • Temperature is constrained to (0.0, 1.0] as required by MiniMax API (defaults to 1.0)
  • Add MiniMax icon for the UI
  • Add 16 unit tests covering model building, temperature handling, model fetching, and error handling

API Reference

Test plan

  • Unit tests pass (src/backend/tests/unit/components/languagemodels/test_minimax.py)
  • Integration test passed: verified MiniMax-M2.7 model responds correctly via api.minimax.io/v1
  • Component follows the same pattern as DeepSeek and xAI components

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for MiniMax language models with API integration and JSON response formatting.
  • Improvements

    • Standardized data type handling across starter projects for improved flow compatibility.
    • Updated component output labels for consistency (DataFrame instead of Table).
  • Dependencies

    • Updated pydantic versions across starter projects.
  • Tests

    • Added unit test coverage for MiniMax language model integration.

- Add MiniMaxModelComponent with OpenAI-compatible API (api.minimax.io/v1)
- Support MiniMax-M2.7 (default) and MiniMax-M2.7-highspeed models
- Add MINIMAX_API_KEY environment variable support
- Temperature constrained to (0.0, 1.0] as required by MiniMax API
- Add MiniMax icon for UI display
- Add 16 unit tests covering build_model, temperature handling, model fetching
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

Walkthrough

The PR standardizes data type handling across starter project flows by removing JSON and Table from ChatOutput's accepted input types, renames Table outputs to DataFrame and JSON outputs to Data throughout multiple starter projects, downgrades pydantic dependencies to 2.11.10, introduces a new MiniMax language model component with frontend icons and unit tests, and updates related module exports.

Changes

Cohort / File(s) Summary
Starter Projects - ChatOutput Type Narrowing
src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json, Basic Prompting.json, Blog Writer.json, Custom Component Generator.json, Document Q&A.json, Financial Report Parser.json, Image Sentiment Analysis.json, Instagram Copywriter.json, Invoice Summarizer.json, Market Research.json, Memory Chatbot.json, Nvidia Remix.json, Pokédex Agent.json, Portfolio Website Code Generator.json, Price Deal Finder.json, Research Agent.json, SEO Keyword Generator.json, SaaS Pricing.json, Search agent.json, Sequential Tasks Agents.json, Simple Agent.json, Social Media Agent.json, Text Sentiment Analysis.json, Travel Planning Agents.json, Twitter Thread Generator.json, Youtube Analysis.json
Removed "JSON" and "Table" from ChatOutput's accepted input types across all starter projects, leaving only "Data", "DataFrame", and "Message". Updated corresponding edge metadata and component code_hash values. Downgraded pydantic dependency from 2.12.5 to 2.11.10 in affected components.
Starter Projects - Output Type Relabeling
Blog Writer.json, Custom Component Generator.json, Market Research.json, Memory Chatbot.json, Meeting Summary.json, Price Deal Finder.json, Research Agent.json, Sequential Tasks Agents.json, Travel Planning Agents.json, Youtube Analysis.json
Renamed component output display names and types from "Table" to "DataFrame" and "JSON" to "Data" in multiple components (ParserComponent, MemoryComponent, TavilySearchComponent, CalculatorComponent, AgentQL, BatchRunComponent) within starter project templates.
Starter Projects - Output Metadata Updates
Hybrid Search RAG.json, Image Sentiment Analysis.json, Market Research.json
Updated output node selected field values from null to explicit type names (e.g., "Data", "VectorStore", "DataFrame") to match configured output types and improve UI consistency.
MiniMax Component Implementation
src/lfx/src/lfx/components/minimax/minimax.py
Introduced new MiniMaxModelComponent class extending LCModelComponent with MiniMax LLM support, including API model fetching via /models endpoint, temperature constraint enforcement, JSON mode output binding, and dynamic build configuration updates.
MiniMax Module Integration
src/lfx/src/lfx/components/minimax/__init__.py, src/lfx/src/lfx/components/__init__.py
Added minimax module initialization with lazy dynamic imports for MiniMaxModelComponent and registered the module in the parent components package's exports and discovery mechanism.
MiniMax Frontend Icons
src/frontend/src/icons/MiniMax/MiniMaxIcon.jsx, src/frontend/src/icons/MiniMax/index.tsx, src/frontend/src/icons/lazyIconImports.ts
Added new React icon components for MiniMax: MiniMaxSVG rendering a rounded rectangle with "MM" text, exported as MiniMaxIcon with ref forwarding, and registered in the lazy icon imports mapping.
MiniMax Unit Tests
src/backend/tests/unit/components/languagemodels/test_minimax.py
Added comprehensive test coverage for MiniMaxModelComponent including metadata verification, model initialization with correct API parameters, temperature normalization, base URL fallback, JSON mode binding, model fetching with API key handling, and error propagation scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested labels

starter-projects, refactor, type-system, components/minimax

Suggested reviewers

  • edwinjosechittilappilly
  • carlosrcoelho
  • jordanrfrazier

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 4 warnings)

Check name Status Explanation Resolution
Test Coverage For New Implementations ❌ Error Test file doesn't inherit from ComponentTestBase and lacks required fixtures (component_class, default_kwargs, file_names_mapping) as mandated by project guidelines. Refactor test_minimax.py to inherit from ComponentTestBase and include required fixtures for component version/backward-compatibility checks.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Quality And Coverage ⚠️ Warning MiniMax test suite lacks proper inheritance from ComponentTestBaseWithoutClient and is missing required fixtures and version/backward-compatibility checks. Migrate test suite to inherit from ComponentTestBaseWithoutClient with required fixtures (component_class, default_kwargs, file_names_mapping) and enhance test coverage.
Test File Naming And Structure ⚠️ Warning Backend test file lacks required ComponentTestBaseWithoutClient inheritance and mandatory fixtures; frontend icon components lack test coverage. Refactor test suite to inherit from ComponentTestBaseWithoutClient with required fixtures and add frontend test file for MiniMax icons with theme variation coverage.
Excessive Mock Usage Warning ⚠️ Warning Test file exhibits excessive mock usage with 7+ mocker.patch() calls, focusing on mock verification rather than actual component behavior testing. Refactor tests to reduce mock dependencies, migrate to ComponentTestBaseWithoutClient, use realistic test doubles, and verify component behavior instead of mock calls.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add MiniMax provider support' clearly and concisely summarizes the primary change: adding MiniMax LLM provider support.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the enhancement New feature or request label Apr 13, 2026
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 13, 2026
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 13, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (18)
src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json (1)

83-88: ⚠️ Potential issue | 🟡 Minor

Keep edge id contract in sync with updated targetHandle.

Line [83] still encodes JSON/Table in the edge id, while Line [88] removes them from targetHandle.inputTypes. Please regenerate/update the edge id to match the new contract.

Proposed fix
-        "id": "reactflow__edge-LanguageModelComponent-FLeYF{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-FLeYFœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-yK0AU{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-yK0AUœ,œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ],œtypeœ:œstrœ}",
+        "id": "reactflow__edge-LanguageModelComponent-FLeYF{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-FLeYFœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-yK0AU{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-yK0AUœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Basic`
Prompting.json around lines 83 - 88, Edge id string for the React Flow edge (the
value of "id" that starts with
"reactflow__edge-LanguageModelComponent-FLeYF-...-ChatOutput-yK0AU") still
encodes JSON and Table in its embedded inputTypes while the "targetHandle" for
ChatOutput-yK0AU now lists inputTypes as [Data, DataFrame, Message];
update/regenerate that edge id to reflect the new contract so the embedded
inputTypes match targetHandle (remove JSON and Table from the encoded id),
ensuring the identifiers LanguageModelComponent-FLeYF and ChatOutput-yK0AU
remain unchanged.
src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json (1)

111-116: ⚠️ Potential issue | 🟡 Minor

Update the serialized edge id too.

Line 111 still embeds the removed JSON/Table types even though Line 116 now exposes only Data/DataFrame/Message. Leaving those out of sync makes the flow JSON internally inconsistent.

🧩 Suggested fix
-        "id": "reactflow__edge-Agent-0vMrI{œdataTypeœ:œAgentœ,œidœ:œAgent-0vMrIœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Lgpwq{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Lgpwqœ,œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ],œtypeœ:œotherœ}",
+        "id": "reactflow__edge-Agent-0vMrI{œdataTypeœ:œAgentœ,œidœ:œAgent-0vMrIœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Lgpwq{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Lgpwqœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Social` Media
Agent.json around lines 111 - 116, The serialized edge "id" is inconsistent with
the updated targetHandle inputTypes; update the edge id string that begins with
"reactflow__edge-Agent-0vMrI{…}-ChatOutput-Lgpwq{…}" so its embedded metadata
matches the sourceHandle/targetHandle values (Agent-0vMrI and ChatOutput-Lgpwq)
— specifically remove the now-removed JSON and Table types from the embedded
output_types/inputTypes in the id so it lists only Data, DataFrame, Message to
match sourceHandle and targetHandle.
src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json (1)

190-194: ⚠️ Potential issue | 🟡 Minor

Keep the edge id aligned with the new handle types.

Line 190 still serializes the old inputTypes (JSON/Table included) while Line 194 has the narrowed contract. That leaves two conflicting sources of truth inside the same edge object and can cause stale round-trips if any importer/parser derives handle metadata from id.

🧩 Suggested fix
-        "id": "xy-edge__LanguageModelComponent-YIUOh{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-YIUOhœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-WSW39{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-WSW39œ,œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ],œtypeœ:œstrœ}",
+        "id": "xy-edge__LanguageModelComponent-YIUOh{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-YIUOhœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-WSW39{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-WSW39œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Basic` Prompt
Chaining.json around lines 190 - 194, The edge object's serialized "id"
currently encodes outdated handle metadata (it includes inputTypes JSON/Table)
that conflicts with the updated "sourceHandle"/"targetHandle"; update the "id"
string for the edge with the same handle metadata as "sourceHandle" and
"targetHandle" (remove JSON and Table from inputTypes, match the exact field
names/types and ordering used in targetHandle/sourceHandle) so the edge id,
sourceHandle and targetHandle are consistent (refer to the existing "id" value,
"sourceHandle" and "targetHandle" fields to align the encoded handle
representation).
src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json (1)

2345-2362: ⚠️ Potential issue | 🟡 Minor

Finish the JSON / TableData / DataFrame rename in the surrounding copy.

This block now exports Data and DataFrame, but the same starter template still calls the parser input JSON or Table at Line 762 and says it produces “structured JSON” at Line 3001. Importing the project will show both naming schemes side by side.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Portfolio` Website
Code Generator.json around lines 2345 - 2362, The starter template still uses
the old wording "JSON / Table" and "structured JSON" while the runtime now emits
"Data" and "DataFrame"; update all user-facing copy in this JSON file to the new
names: rename any input label or help text that says "JSON" or "JSON or Table"
to "Data" (or "Data input") and change any occurrences of "structured JSON" to
"structured DataFrame" (or "structured Data") so they match the method name
build_structured_dataframe and the output node dataframe_output; search for
display_name, description, title, help_text, and any parser/input label strings
and replace accordingly.
src/backend/base/langflow/initial_setup/starter_projects/Nvidia Remix.json (1)

55-60: ⚠️ Potential issue | 🟡 Minor

Regenerate the edge ID after narrowing the handle types.

Line 60 updates the serialized targetHandle, but Line 55 still bakes the old ["Data","JSON","DataFrame","Table","Message"] signature into the edge id. That leaves this flow internally inconsistent and can create stale or duplicate edge identities when the project is loaded or re-saved.

🩹 Suggested fix
-        "id": "reactflow__edge-Agent-9dON7{œdataTypeœ:œAgentœ,œidœ:œAgent-9dON7œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-o3obj{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-o3objœ,œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ],œtypeœ:œotherœ}",
+        "id": "reactflow__edge-Agent-9dON7{œdataTypeœ:œAgentœ,œidœ:œAgent-9dON7œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-o3obj{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-o3objœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Nvidia` Remix.json
around lines 55 - 60, The edge object has an outdated id that still encodes the
old targetHandle types; regenerate the "id" for the edge connecting source
"Agent-9dON7" to target "ChatOutput-o3obj" so it reflects the updated
"targetHandle" signature (the trimmed inputTypes removing JSON/Table), using the
same id-generation logic the app uses for edges (i.e., compose id from source,
sourceHandle, target, targetHandle) so the serialized id and the
"targetHandle"/"sourceHandle" stay consistent and avoid stale/duplicate edge
identities.
src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json (1)

111-116: ⚠️ Potential issue | 🟡 Minor

Regenerate the edge IDs after changing targetHandle.inputTypes.

targetHandle now advertises ["Data", "DataFrame", "Message"], but both serialized edge id values still embed the removed JSON/Table types. That leaves this snapshot internally inconsistent and can cause the editor to recreate these edges with new IDs the next time the flow is regenerated or re-saved.

Suggested fix
-        "id": "reactflow__edge-LanguageModelComponent-ZLKtg{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-ZLKtgœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-h5fAd{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-h5fAdœ,œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ],œtypeœ:œotherœ}",
+        "id": "reactflow__edge-LanguageModelComponent-ZLKtg{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-ZLKtgœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-h5fAd{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-h5fAdœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}",

-        "id": "reactflow__edge-LanguageModelComponent-dZixZ{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-dZixZœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-DVXkn{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DVXknœ,œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ],œtypeœ:œotherœ}",
+        "id": "reactflow__edge-LanguageModelComponent-dZixZ{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-dZixZœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-DVXkn{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DVXknœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}",

Also applies to: 169-174

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Text` Sentiment
Analysis.json around lines 111 - 116, The serialized edge objects contain stale
IDs that embed old inputTypes (e.g., the "id" field starting with
"reactflow__edge-LanguageModelComponent-ZLKtg...-ChatOutput-h5fAd") which no
longer match the updated targetHandle.inputTypes (now
["Data","DataFrame","Message"]); update/regenerate the edge IDs for these edges
so the embedded handle/type lists reflect the current sourceHandle/targetHandle
values (search for edges referencing LanguageModelComponent-ZLKtg and
ChatOutput-h5fAd and replace their "id" strings to match the current serialized
sourceHandle/targetHandle), and apply the same fix to the other occurrence noted
(the block around the second edge at the later lines).
src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json (1)

83-88: ⚠️ Potential issue | 🟡 Minor

Edge ID contains stale type information.

The edge id at line 83 still references the old inputTypes list including JSON and Table, while the targetHandle at line 88 and data.targetHandle.inputTypes (lines 75-79) have been correctly updated to ["Data", "DataFrame", "Message"].

While ReactFlow edge IDs are typically used only as unique identifiers, this inconsistency could cause confusion during maintenance. Consider regenerating the edge ID to match the updated type contract, or leaving a note if this is expected behavior for backward compatibility.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Document` Q&A.json
around lines 83 - 88, The edge id string for the reactflow edge connecting
LanguageModelComponent-htMuI -> ChatOutput-bcQIH still includes the old
inputTypes (JSON, Table); update/regenerate the "id" value to reflect the
current inputTypes ("Data", "DataFrame", "Message") so it matches the
targetHandle and data.targetHandle.inputTypes, i.e., replace the stale type list
inside the id (the long string starting with
reactflow__edge-LanguageModelComponent-htMuI…) or, if you intentionally preserve
the old id for compatibility, add a brief inline comment in the JSON indicating
that the id is intentionally versioned/stale.
src/backend/base/langflow/initial_setup/starter_projects/Search agent.json (1)

25-29: ⚠️ Potential issue | 🟡 Minor

Update the edge id to match the narrowed targetHandle.

The handle contract was reduced to Data/DataFrame/Message, but the serialized edge id still contains JSON and Table. Keeping both forms out of sync makes the exported graph inconsistent and can cause round-trip save noise.

♻️ Proposed fix
- "id": "...œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ]..."
+ "id": "...œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ]..."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Search` agent.json
around lines 25 - 29, The serialized edge id string for the edge
"xy-edge__Agent-9JGgQ...-ChatOutput-Pygov" is out of sync with its narrowed
targetHandle (ChatOutput-Pygov) — it still lists JSON and Table in the embedded
inputTypes; update the edge "id" value to match the targetHandle's inputTypes
([Data, DataFrame, Message]) by removing JSON and Table so the embedded handle
in the id exactly mirrors the "targetHandle" field (ensure the same
fieldName/id/inputTypes/type tokens are used).
src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json (1)

56-61: ⚠️ Potential issue | 🟡 Minor

Regenerate the serialized edge ID after changing the handle types.

targetHandle now advertises only Data/DataFrame/Message, but the edge id still embeds JSON and Table. That leaves this saved flow internally inconsistent and can cause needless diff churn or a duplicate edge on the next round-trip save.

♻️ Proposed fix
- "id": "...œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ]..."
+ "id": "...œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ]..."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Instagram`
Copywriter.json around lines 56 - 61, The serialized edge "id" for the edge
between source Prompt-vj0Ef and target ChatOutput-xm3UQ embeds obsolete handle
types (JSON, Table) and must be regenerated to match the current targetHandle's
inputTypes ([Data, DataFrame, Message]); update the value of the "id" string
that starts with "reactflow__edge-Prompt-vj0Ef{...}-ChatOutput-xm3UQ{...}" so
its embedded serialized handle section for the target matches the targetHandle
field (remove JSON and Table and keep the canonical ordering/format), ensuring
the edge id, "source": "Prompt-vj0Ef" and "target": "ChatOutput-xm3UQ" stay
consistent with the handle serialization to avoid diff churn/duplicate edges on
save.
src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json (1)

96-112: ⚠️ Potential issue | 🟡 Minor

Regenerate the ChatOutput serialization.

This update changes input_value to a HandleInput, but the same node still serializes template.input_value as _input_type: "MessageInput" / type: "str", and the connected edge still uses type: "str" with the old handle signature embedded in its id. That leaves the starter flow with conflicting definitions for the same input and can break round-tripping or editing after import.

Also applies to: 397-484

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Invoice`
Summarizer.json around lines 96 - 112, The ChatOutput node serialization is out
of date: template.input_value was converted to a HandleInput but the node still
emits _input_type/ type as the old MessageInput/str and the connecting edge
id/targetHandle retains the old handle signature; update the ChatOutput
serialization (the node with id "ChatOutput-Acmbw" and its template.input_value)
to emit the correct HandleInput metadata (set _input_type to HandleInput and
adjust type/field descriptors accordingly) and regenerate the connected edge
representation (the edge whose source is "Agent-CBCVT" and id containing
"xy-edge__Agent-CBCVT...-ChatOutput-Acmbw") so its id, targetHandle, and
inputTypes reflect the new handle signature and inputTypes list; apply the same
fix to the other occurrences referenced around lines 397-484 to ensure
consistent round-trippable definitions.
src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json (1)

27-32: ⚠️ Potential issue | 🟡 Minor

Regenerate this edge ID too.

Line 27 still serializes the old ChatOutput handle types, but Line 32 narrows the actual targetHandle to ["Data","DataFrame","Message"]. That mismatch leaves stale edge metadata in the starter project and is likely to be rewritten later anyway.

♻️ Proposed fix
- œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ]
+ œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Simple` Agent.json
around lines 27 - 32, The edge ID string for the connection between Agent-oYRYa
and ChatOutput-z90NZ embeds stale handle metadata (sourceHandle includes
JSON/Table while targetHandle is narrowed to ["Data","DataFrame","Message"]);
regenerate the edge identifier and its serialized handle fields so they match
the actual targetHandle (remove JSON and Table from the serialized types) —
update the "id" value and the "sourceHandle"/"targetHandle" entries for the
Agent-oYRYa -> ChatOutput-z90NZ edge so all embedded handle/type lists are
consistent.
src/backend/base/langflow/initial_setup/starter_projects/Custom Component Generator.json (1)

171-176: ⚠️ Potential issue | 🟡 Minor

Update the serialized edge ID to match the new handle signature.

Line 171 still encodes the old ["Data","JSON","DataFrame","Table","Message"] payload, while Line 176 now uses ["Data","DataFrame","Message"]. Leaving those out of sync makes the saved flow internally contradictory and can cause unnecessary edge churn on the next import/save cycle.

♻️ Proposed fix
- œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ]
+ œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Custom` Component
Generator.json around lines 171 - 176, The serialized edge id value for the edge
connecting LanguageModelComponent-SCqm9 -> ChatOutput-VoIob is out of sync with
the updated handle signature: update the "id" field that begins with
reactflow__edge-LanguageModelComponent-SCqm9... so its embedded source/target
handle payload matches the new sourceHandle/targetHandle arrays (i.e., remove
"JSON" and "Table" from the encoded inputTypes/output_types so it reflects
["Data","DataFrame","Message"] / ["Message"] as used by the sourceHandle and
targetHandle), ensuring the id payload for LanguageModelComponent-SCqm9 and
ChatOutput-VoIob is consistent with the new handle representation.
src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json (1)

27-32: ⚠️ Potential issue | 🟡 Minor

Keep the serialized edge IDs in sync with the updated handle metadata.

The connection metadata was updated from JSON/Table to Data/DataFrame, but both edge id strings still encode the old signatures. That mismatch can leave the starter flow in a stale state the next time the editor rehydrates or rewrites the graph.

Also applies to: 58-63

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Image` Sentiment
Analysis.json around lines 27 - 32, The serialized edge id strings still encode
the old handle metadata (JSON/Table) for the edge connecting parser-IFSS9 ->
ChatOutput-Ou5RJ; update those edge "id" and any other serialized edge
identifiers (e.g., the entry at lines referencing parser-IFSS9 and
ChatOutput-Ou5RJ, including the ones noted at 58-63) so their encoded signatures
match the current handle metadata (replace JSON/Table with Data/DataFrame and
ensure inputTypes/output_types arrays and field/type names match the
target/source handle objects exactly) to keep the editor rehydration consistent.
src/backend/base/langflow/initial_setup/starter_projects/Market Research.json (1)

83-88: ⚠️ Potential issue | 🟡 Minor

Regenerate the edge IDs after renaming the handle types.

These edges now serialize sourceHandle/targetHandle as Data/DataFrame, but the persisted id strings still embed the old JSON/Table signatures. That leaves the saved graph internally inconsistent and can cause reconnect/duplicate-edge issues when the flow is edited again.

Also applies to: 140-145

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Market`
Research.json around lines 83 - 88, Edge objects have mismatched serialized
handle type names: sourceHandle/targetHandle were renamed to Data/DataFrame but
the embedded id string (e.g., the "id" value containing ParserComponent-8lfAE
and ChatOutput-tjFWM) still contains old JSON/Table signatures; update the edge
id strings to reflect the current handle types so they match
sourceHandle/targetHandle (for example regenerate the id for the edge linking
ParserComponent-8lfAE -> ChatOutput-tjFWM to include Data/DataFrame instead of
JSON/Table), and apply the same fix to the other affected edges mentioned (lines
140-145) so saved graph IDs are consistent with the handle definitions.
src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json (2)

532-672: ⚠️ Potential issue | 🟠 Major

Finish regenerating the ChatOutput node snapshot.

The embedded code now defines input_value as a HandleInput, but the serialized field below is still a plain string input (type: "str" with no _input_type). That means this starter project can load with a ChatOutput schema that disagrees with its own component snapshot, and it explains why the LanguageModel -> ChatOutput edge still carries a stale string handle type. Compare this with src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json:1888-1908, where the same field is serialized as _input_type: "HandleInput" / type: "other".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Blog` Writer.json
around lines 532 - 672, The snapshot for the ChatOutput component has a
mismatch: the component's inputs declare a HandleInput named "input_value" but
the serialized snapshot field "input_value" is still a plain string (type:
"str"); update the snapshot to match the component by serializing "input_value"
with "_input_type": "HandleInput" and the appropriate serialized type (e.g.,
"type": "other") and preserve the input metadata (input_types, required,
display_name, trace flags) so the component schema and snapshot agree; look for
the ChatOutput class and the snapshot entry for input_value to make this change.

63-89: ⚠️ Potential issue | 🟠 Major

Regenerate the edge ID when you rewrite the handle types.

This edge now advertises page_results -> input_data as DataFrame/Data, but the persisted id still bakes in the old Table/JSON metadata. That mismatch leaves the saved graph inconsistent and can create a second edge when the editor rewrites the connection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Blog` Writer.json
around lines 63 - 89, The persisted edge id string (the "id" field for the edge
connecting source "URLComponent-DFXG5" to target "ParserComponent-YRRd0") still
contains the old handle metadata (e.g. "Table"/"JSON") while the live
sourceHandle/targetHandle objects have been rewritten to "DataFrame"/"Data",
causing an inconsistent graph and duplicate edges; fix this by regenerating the
edge id whenever you update handle types: when modifying
URLComponent-DFXG5.sourceHandle or ParserComponent-YRRd0.targetHandle, construct
the canonical handle serialization (the same format used for sourceHandle and
targetHandle string fields) from the new output_types/inputTypes and include it
in the edge id and in the sourceHandle/targetHandle string representations so
the "id" value, "sourceHandle" string, and "targetHandle" string remain in sync
with the handle objects and prevent creation of a second edge.
src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json (1)

186-202: ⚠️ Potential issue | 🟠 Major

Regenerate this edge ID after narrowing the handle contract.

The id string still encodes the old ["Data", "JSON", "DataFrame", "Table", "Message"] target types, while the actual targetHandle now advertises ["Data", "DataFrame", "Message"]. That leaves the saved flow internally inconsistent and can create duplicate/recreated edges once the graph is edited or re-saved.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Research` Agent.json
around lines 186 - 202, The edge's serialized "id" is inconsistent with the
updated targetHandle.inputTypes; update the reactflow edge id string (the value
of "id" that begins with
"reactflow__edge-LanguageModelComponent-80mt4...-ChatOutput-gZuRk...") so it
encodes the current targetHandle inputTypes ["Data","DataFrame","Message"] (and
matches the sourceHandle payload for LanguageModelComponent-80mt4 and the target
ChatOutput-gZuRk) to avoid duplicate/recreated edges; ensure the "id",
"sourceHandle" and "targetHandle" serialized fragments are regenerated together
so all encoded type lists and handle ids (LanguageModelComponent-80mt4,
ChatOutput-gZuRk, output_types/message) stay consistent.
src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json (1)

75-79: ⚠️ Potential issue | 🟡 Minor

Edge ID and targetHandle mismatch could cause deserialization or edge-matching issues.

The edge id on line 75 still embeds the old inputTypes array including "JSON" and "Table":

œinputTypesœ:[œDataœ,œJSONœ,œDataFrameœ,œTableœ,œMessageœ]

However, the targetHandle on line 79 has been updated to only ["Data", "DataFrame", "Message"]. If the application uses edge IDs for validation or matching against handle definitions, this inconsistency could cause edge resolution failures or warnings during flow loading.

Consider regenerating the edge ID to match the updated targetHandle, or verify that edge IDs are not used for strict matching against handle metadata.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Pokédex` Agent.json
around lines 75 - 79, The edge ID string for the connection between Agent-R27kt
and ChatOutput-lbrgJ embeds an outdated inputTypes list (includes "JSON" and
"Table") that no longer matches the targetHandle inputTypes
["Data","DataFrame","Message"]; update/regenerate the edge id value (the long
string beginning with xy-edge__Agent-R27kt{…}-ChatOutput-lbrgJ) so its embedded
metadata's inputTypes exactly mirror the targetHandle, and scan for any other
references to the old edge id to update them or confirm edge IDs are not relied
upon for strict matching.
🧹 Nitpick comments (1)
src/backend/tests/unit/components/languagemodels/test_minimax.py (1)

25-28: Avoid coupling the template test to private _code.

Rebuilding the component from component._code makes this test brittle to internal representation changes. Prefer exercising the public frontend-node/template path directly so the test tracks the same contract the UI uses. As per coding guidelines, component frontend/build-config tests should be driven from the component’s frontend node rather than private internals.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/tests/unit/components/languagemodels/test_minimax.py` around
lines 25 - 28, The test is brittle because it reconstructs a Component from the
private MiniMaxModelComponent._code; instead, obtain the component's public
frontend node/template and pass that to build_custom_component_template. Replace
use of Component(_code=component._code) with the component's public API (e.g.,
component.frontend_node or component.build_frontend_node()/to_frontend_node())
and call build_custom_component_template(frontend_node) using that value so the
test exercises the same frontend contract as the UI (references:
MiniMaxModelComponent, Component, build_custom_component_template,
frontend_node).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/backend/base/langflow/initial_setup/starter_projects/Financial` Report
Parser.json:
- Line 1442: The convert_to_string method wrongly coerces inputs with "or False"
and uses self.clean_data or False; update both usages to pass the original
object and use getattr to read the optional clean_data attribute: in
convert_to_string replace safe_convert(item, clean_data=self.clean_data or
False) with safe_convert(item, clean_data=getattr(self, "clean_data", False))
and replace safe_convert(self.input_data or False) with
safe_convert(self.input_data, clean_data=getattr(self, "clean_data", False));
ensure Message creation and self.status assignment remain the same.

In `@src/backend/base/langflow/initial_setup/starter_projects/Meeting`
Summary.json:
- Around line 1755-1762: The visible Memory output label "display_name":
"Dataframe" is inconsistent with the migrated type "DataFrame"; update the
display_name (and any embedded component definition labels) to "DataFrame" so
the UI matches the metadata (look for entries with name: "dataframe", method:
"retrieve_messages_dataframe", selected: "DataFrame" and change display_name
from "Dataframe" to "DataFrame", also apply the same change at the other
occurrence around the embedded component definition referenced in the diff).

In `@src/backend/base/langflow/initial_setup/starter_projects/Memory`
Chatbot.json:
- Around line 960-967: Replace the inconsistent lowercase label "Dataframe" with
the canonical "DataFrame" wherever the Message History output is defined (e.g.,
the JSON property "display_name": "Dataframe" in the starter project and any
embedded component definitions tied to the node with "method":
"retrieve_messages_dataframe" and "name": "dataframe"); ensure the visible label
matches the "selected": "DataFrame" value and update the other occurrence noted
near the embedded component so both places use "DataFrame" exactly.

In `@src/backend/base/langflow/initial_setup/starter_projects/SEO` Keyword
Generator.json:
- Line 60: The targetHandle value is malformed using non-JSON delimiters (œ)
which breaks downstream parsing; locate the "targetHandle" entry (contains
"ChatOutput-S7Bzs", "œfieldNameœ", "œinput_valueœ") and replace the œ delimiters
with proper JSON-escaped double quotes so the value is a valid JSON string
(matching the other escaped JSON handle payloads in this file), preserving the
same keys ("fieldName", "id", "inputTypes", "type") and array contents.

In `@src/backend/base/langflow/initial_setup/starter_projects/Sequential` Tasks
Agents.json:
- Line 314: The ChatOutput alias usage in this snapshot is inconsistent: the
targetHandle and other serialized places (e.g., edge ID and
YfinanceComponent.base_classes) use the new narrowed set
["Data","DataFrame","Message"] while other parts still serialize legacy aliases
("JSON","Table"), causing runtime contract mismatch with
src/lfx/src/lfx/components/input_output/chat_output.py; fix by migrating the
entire snapshot to a consistent alias set or preserve backward compatibility by
including both sets wherever ChatOutput appears (update the "targetHandle"
entries, the edge ids, and YfinanceComponent.base_classes to either the new
canonical aliases or a combined array
["Data","DataFrame","Message","JSON","Table"] so the embedded components match
the canonical ChatOutput contract).

In `@src/backend/base/langflow/initial_setup/starter_projects/Travel` Planning
Agents.json:
- Line 144: The patch only updates the serialized targetHandle string but leaves
the edge object’s other fields (notably the edge "id" that encodes the old
JSON/Table signature) inconsistent; regenerate the entire edge object for this
connection so all fields are consistent (update the edge "id", "targetHandle",
and any related signature/meta in the same edge block) instead of editing only
targetHandle, locating the edge by its current id and the "targetHandle"
property in the Travel Planning Agents.json file and replacing the whole edge
entry atomically.
- Line 573: The ChatOutput embedded snapshot's input handle types are out of
sync with the real component; update the HandleInput named "input_value" in
class ChatOutput to include the same input_types as the real component (Data,
JSON, DataFrame, Table, Message) instead of only ["Data", "DataFrame",
"Message"], and ensure any serialized/embedded edge metadata or handle signature
stored in this JSON (the old handle signature referenced in the comment) is
updated to reflect the new input_types so starter flows import with the correct
contract.

In `@src/backend/base/langflow/initial_setup/starter_projects/Youtube`
Analysis.json:
- Line 60: The flow's serialized edge payloads were updated to use handle types
"Data"/"DataFrame" but some sibling edge IDs still encode the old "JSON"/"Table"
signature (e.g., the targetHandle entry with "ChatOutput-JZAp9"); regenerate the
affected edge IDs so their serialized signatures reflect the new handle types.
Locate entries that contain "targetHandle" and edge id strings (like
"ChatOutput-JZAp9") and re-create or re-hash those edge IDs so they include the
updated handle type names (Data/DataFrame) instead of the old JSON/Table tokens,
ensuring all sibling edges referencing the same handle payloads use the same
regenerated IDs for consistency.

In `@src/backend/tests/unit/components/languagemodels/test_minimax.py`:
- Around line 230-238: Replace the no-op assertions in
test_minimax_update_build_config with assertions that verify real mutations:
instantiate MiniMaxModelComponent, call its to_frontend_node() to obtain the
initial build_config/node template, then call
component.update_build_config(build_config, "test-key", "api_key") and assert
the specific option/value changes inside the returned config (e.g., that the
"api_key" option exists/was added under the correct model key and contains
"test-key"); repeat similarly for update_build_config(build_config,
"MiniMax-M2.7", "model_name") and assert the model_name option was set/updated
to "MiniMax-M2.7". Ensure you reference MiniMaxModelComponent,
to_frontend_node(), and update_build_config() when locating where to change the
test.
- Around line 11-255: The test suite should be converted to use the standard
component test harness by creating a test class that inherits from
ComponentTestBaseWithoutClient and providing the required fixtures:
component_class (pointing to MiniMaxModelComponent), default_kwargs (a dict with
minimal valid kwargs like api_key, model_name, base_url, etc.), and
file_names_mapping (as required by the harness). Move the existing standalone
pytest functions into methods on that class (or keep them as module-level tests
that reuse the provided fixtures) and update any direct construction of
MiniMaxModelComponent() to rely on the component_class/default_kwargs fixtures
where appropriate; keep special-case tests (like get_models HTTP mocks,
json_mode, and error handling) but adapt them to use the harness fixtures and
ensure names reference MiniMaxModelComponent, build_model, get_models,
update_build_config, and MINIMAX_MODELS so the harness runs the standard
version/backward-compat checks.

In `@src/frontend/src/icons/MiniMax/MiniMaxIcon.jsx`:
- Line 16: The SVG fill uses the same color for both branches so dark mode never
changes; update the conditional in the MiniMaxIcon component (where it uses
props.isDark) to choose different colors for dark vs light (for example
fill={props.isDark ? "#ffffff" : "#0A0A0A"}), and apply the same fix to the
second occurrence referenced (the other fill at the same component), ensuring
both places use distinct dark and light hex values or design tokens.

In `@src/lfx/src/lfx/components/minimax/minimax.py`:
- Around line 100-108: In get_models(), Ruff flags TRY300 because the try block
contains a return; move the success-path return out of the try by computing the
response, parsing data and building models inside the try (keeping
response.raise_for_status()), then add an else: block after the except to return
models if present or MINIMAX_MODELS; keep the except handling setting
self.status and returning MINIMAX_MODELS unchanged. Reference: function
get_models, MINIMAX_MODELS, requests.get, requests.RequestException,
response.raise_for_status(), data = response.json().
- Around line 91-108: The Authorization header is using a masked SecretStr
instead of the real API key; in get_models (and similarly in build_model) detect
if self.api_key is a pydantic SecretStr and call .get_secret_value() to unwrap
it before interpolating into headers (use isinstance(self.api_key, SecretStr) or
similar), do not re-wrap an already-SecretStr value with SecretStr()—always
extract the raw string when making network requests and then set
headers={"Authorization": f"Bearer {unwrapped_api_key}", ...}; update
build_model to also unwrap any provided api_key parameter via
.get_secret_value() if it's a SecretStr.

---

Outside diff comments:
In `@src/backend/base/langflow/initial_setup/starter_projects/Basic` Prompt
Chaining.json:
- Around line 190-194: The edge object's serialized "id" currently encodes
outdated handle metadata (it includes inputTypes JSON/Table) that conflicts with
the updated "sourceHandle"/"targetHandle"; update the "id" string for the edge
with the same handle metadata as "sourceHandle" and "targetHandle" (remove JSON
and Table from inputTypes, match the exact field names/types and ordering used
in targetHandle/sourceHandle) so the edge id, sourceHandle and targetHandle are
consistent (refer to the existing "id" value, "sourceHandle" and "targetHandle"
fields to align the encoded handle representation).

In `@src/backend/base/langflow/initial_setup/starter_projects/Basic`
Prompting.json:
- Around line 83-88: Edge id string for the React Flow edge (the value of "id"
that starts with
"reactflow__edge-LanguageModelComponent-FLeYF-...-ChatOutput-yK0AU") still
encodes JSON and Table in its embedded inputTypes while the "targetHandle" for
ChatOutput-yK0AU now lists inputTypes as [Data, DataFrame, Message];
update/regenerate that edge id to reflect the new contract so the embedded
inputTypes match targetHandle (remove JSON and Table from the encoded id),
ensuring the identifiers LanguageModelComponent-FLeYF and ChatOutput-yK0AU
remain unchanged.

In `@src/backend/base/langflow/initial_setup/starter_projects/Blog` Writer.json:
- Around line 532-672: The snapshot for the ChatOutput component has a mismatch:
the component's inputs declare a HandleInput named "input_value" but the
serialized snapshot field "input_value" is still a plain string (type: "str");
update the snapshot to match the component by serializing "input_value" with
"_input_type": "HandleInput" and the appropriate serialized type (e.g., "type":
"other") and preserve the input metadata (input_types, required, display_name,
trace flags) so the component schema and snapshot agree; look for the ChatOutput
class and the snapshot entry for input_value to make this change.
- Around line 63-89: The persisted edge id string (the "id" field for the edge
connecting source "URLComponent-DFXG5" to target "ParserComponent-YRRd0") still
contains the old handle metadata (e.g. "Table"/"JSON") while the live
sourceHandle/targetHandle objects have been rewritten to "DataFrame"/"Data",
causing an inconsistent graph and duplicate edges; fix this by regenerating the
edge id whenever you update handle types: when modifying
URLComponent-DFXG5.sourceHandle or ParserComponent-YRRd0.targetHandle, construct
the canonical handle serialization (the same format used for sourceHandle and
targetHandle string fields) from the new output_types/inputTypes and include it
in the edge id and in the sourceHandle/targetHandle string representations so
the "id" value, "sourceHandle" string, and "targetHandle" string remain in sync
with the handle objects and prevent creation of a second edge.

In `@src/backend/base/langflow/initial_setup/starter_projects/Custom` Component
Generator.json:
- Around line 171-176: The serialized edge id value for the edge connecting
LanguageModelComponent-SCqm9 -> ChatOutput-VoIob is out of sync with the updated
handle signature: update the "id" field that begins with
reactflow__edge-LanguageModelComponent-SCqm9... so its embedded source/target
handle payload matches the new sourceHandle/targetHandle arrays (i.e., remove
"JSON" and "Table" from the encoded inputTypes/output_types so it reflects
["Data","DataFrame","Message"] / ["Message"] as used by the sourceHandle and
targetHandle), ensuring the id payload for LanguageModelComponent-SCqm9 and
ChatOutput-VoIob is consistent with the new handle representation.

In `@src/backend/base/langflow/initial_setup/starter_projects/Document` Q&A.json:
- Around line 83-88: The edge id string for the reactflow edge connecting
LanguageModelComponent-htMuI -> ChatOutput-bcQIH still includes the old
inputTypes (JSON, Table); update/regenerate the "id" value to reflect the
current inputTypes ("Data", "DataFrame", "Message") so it matches the
targetHandle and data.targetHandle.inputTypes, i.e., replace the stale type list
inside the id (the long string starting with
reactflow__edge-LanguageModelComponent-htMuI…) or, if you intentionally preserve
the old id for compatibility, add a brief inline comment in the JSON indicating
that the id is intentionally versioned/stale.

In `@src/backend/base/langflow/initial_setup/starter_projects/Image` Sentiment
Analysis.json:
- Around line 27-32: The serialized edge id strings still encode the old handle
metadata (JSON/Table) for the edge connecting parser-IFSS9 -> ChatOutput-Ou5RJ;
update those edge "id" and any other serialized edge identifiers (e.g., the
entry at lines referencing parser-IFSS9 and ChatOutput-Ou5RJ, including the ones
noted at 58-63) so their encoded signatures match the current handle metadata
(replace JSON/Table with Data/DataFrame and ensure inputTypes/output_types
arrays and field/type names match the target/source handle objects exactly) to
keep the editor rehydration consistent.

In `@src/backend/base/langflow/initial_setup/starter_projects/Instagram`
Copywriter.json:
- Around line 56-61: The serialized edge "id" for the edge between source
Prompt-vj0Ef and target ChatOutput-xm3UQ embeds obsolete handle types (JSON,
Table) and must be regenerated to match the current targetHandle's inputTypes
([Data, DataFrame, Message]); update the value of the "id" string that starts
with "reactflow__edge-Prompt-vj0Ef{...}-ChatOutput-xm3UQ{...}" so its embedded
serialized handle section for the target matches the targetHandle field (remove
JSON and Table and keep the canonical ordering/format), ensuring the edge id,
"source": "Prompt-vj0Ef" and "target": "ChatOutput-xm3UQ" stay consistent with
the handle serialization to avoid diff churn/duplicate edges on save.

In `@src/backend/base/langflow/initial_setup/starter_projects/Invoice`
Summarizer.json:
- Around line 96-112: The ChatOutput node serialization is out of date:
template.input_value was converted to a HandleInput but the node still emits
_input_type/ type as the old MessageInput/str and the connecting edge
id/targetHandle retains the old handle signature; update the ChatOutput
serialization (the node with id "ChatOutput-Acmbw" and its template.input_value)
to emit the correct HandleInput metadata (set _input_type to HandleInput and
adjust type/field descriptors accordingly) and regenerate the connected edge
representation (the edge whose source is "Agent-CBCVT" and id containing
"xy-edge__Agent-CBCVT...-ChatOutput-Acmbw") so its id, targetHandle, and
inputTypes reflect the new handle signature and inputTypes list; apply the same
fix to the other occurrences referenced around lines 397-484 to ensure
consistent round-trippable definitions.

In `@src/backend/base/langflow/initial_setup/starter_projects/Market`
Research.json:
- Around line 83-88: Edge objects have mismatched serialized handle type names:
sourceHandle/targetHandle were renamed to Data/DataFrame but the embedded id
string (e.g., the "id" value containing ParserComponent-8lfAE and
ChatOutput-tjFWM) still contains old JSON/Table signatures; update the edge id
strings to reflect the current handle types so they match
sourceHandle/targetHandle (for example regenerate the id for the edge linking
ParserComponent-8lfAE -> ChatOutput-tjFWM to include Data/DataFrame instead of
JSON/Table), and apply the same fix to the other affected edges mentioned (lines
140-145) so saved graph IDs are consistent with the handle definitions.

In `@src/backend/base/langflow/initial_setup/starter_projects/Nvidia` Remix.json:
- Around line 55-60: The edge object has an outdated id that still encodes the
old targetHandle types; regenerate the "id" for the edge connecting source
"Agent-9dON7" to target "ChatOutput-o3obj" so it reflects the updated
"targetHandle" signature (the trimmed inputTypes removing JSON/Table), using the
same id-generation logic the app uses for edges (i.e., compose id from source,
sourceHandle, target, targetHandle) so the serialized id and the
"targetHandle"/"sourceHandle" stay consistent and avoid stale/duplicate edge
identities.

In `@src/backend/base/langflow/initial_setup/starter_projects/Pokédex` Agent.json:
- Around line 75-79: The edge ID string for the connection between Agent-R27kt
and ChatOutput-lbrgJ embeds an outdated inputTypes list (includes "JSON" and
"Table") that no longer matches the targetHandle inputTypes
["Data","DataFrame","Message"]; update/regenerate the edge id value (the long
string beginning with xy-edge__Agent-R27kt{…}-ChatOutput-lbrgJ) so its embedded
metadata's inputTypes exactly mirror the targetHandle, and scan for any other
references to the old edge id to update them or confirm edge IDs are not relied
upon for strict matching.

In `@src/backend/base/langflow/initial_setup/starter_projects/Portfolio` Website
Code Generator.json:
- Around line 2345-2362: The starter template still uses the old wording "JSON /
Table" and "structured JSON" while the runtime now emits "Data" and "DataFrame";
update all user-facing copy in this JSON file to the new names: rename any input
label or help text that says "JSON" or "JSON or Table" to "Data" (or "Data
input") and change any occurrences of "structured JSON" to "structured
DataFrame" (or "structured Data") so they match the method name
build_structured_dataframe and the output node dataframe_output; search for
display_name, description, title, help_text, and any parser/input label strings
and replace accordingly.

In `@src/backend/base/langflow/initial_setup/starter_projects/Research`
Agent.json:
- Around line 186-202: The edge's serialized "id" is inconsistent with the
updated targetHandle.inputTypes; update the reactflow edge id string (the value
of "id" that begins with
"reactflow__edge-LanguageModelComponent-80mt4...-ChatOutput-gZuRk...") so it
encodes the current targetHandle inputTypes ["Data","DataFrame","Message"] (and
matches the sourceHandle payload for LanguageModelComponent-80mt4 and the target
ChatOutput-gZuRk) to avoid duplicate/recreated edges; ensure the "id",
"sourceHandle" and "targetHandle" serialized fragments are regenerated together
so all encoded type lists and handle ids (LanguageModelComponent-80mt4,
ChatOutput-gZuRk, output_types/message) stay consistent.

In `@src/backend/base/langflow/initial_setup/starter_projects/Search` agent.json:
- Around line 25-29: The serialized edge id string for the edge
"xy-edge__Agent-9JGgQ...-ChatOutput-Pygov" is out of sync with its narrowed
targetHandle (ChatOutput-Pygov) — it still lists JSON and Table in the embedded
inputTypes; update the edge "id" value to match the targetHandle's inputTypes
([Data, DataFrame, Message]) by removing JSON and Table so the embedded handle
in the id exactly mirrors the "targetHandle" field (ensure the same
fieldName/id/inputTypes/type tokens are used).

In `@src/backend/base/langflow/initial_setup/starter_projects/Simple` Agent.json:
- Around line 27-32: The edge ID string for the connection between Agent-oYRYa
and ChatOutput-z90NZ embeds stale handle metadata (sourceHandle includes
JSON/Table while targetHandle is narrowed to ["Data","DataFrame","Message"]);
regenerate the edge identifier and its serialized handle fields so they match
the actual targetHandle (remove JSON and Table from the serialized types) —
update the "id" value and the "sourceHandle"/"targetHandle" entries for the
Agent-oYRYa -> ChatOutput-z90NZ edge so all embedded handle/type lists are
consistent.

In `@src/backend/base/langflow/initial_setup/starter_projects/Social` Media
Agent.json:
- Around line 111-116: The serialized edge "id" is inconsistent with the updated
targetHandle inputTypes; update the edge id string that begins with
"reactflow__edge-Agent-0vMrI{…}-ChatOutput-Lgpwq{…}" so its embedded metadata
matches the sourceHandle/targetHandle values (Agent-0vMrI and ChatOutput-Lgpwq)
— specifically remove the now-removed JSON and Table types from the embedded
output_types/inputTypes in the id so it lists only Data, DataFrame, Message to
match sourceHandle and targetHandle.

In `@src/backend/base/langflow/initial_setup/starter_projects/Text` Sentiment
Analysis.json:
- Around line 111-116: The serialized edge objects contain stale IDs that embed
old inputTypes (e.g., the "id" field starting with
"reactflow__edge-LanguageModelComponent-ZLKtg...-ChatOutput-h5fAd") which no
longer match the updated targetHandle.inputTypes (now
["Data","DataFrame","Message"]); update/regenerate the edge IDs for these edges
so the embedded handle/type lists reflect the current sourceHandle/targetHandle
values (search for edges referencing LanguageModelComponent-ZLKtg and
ChatOutput-h5fAd and replace their "id" strings to match the current serialized
sourceHandle/targetHandle), and apply the same fix to the other occurrence noted
(the block around the second edge at the later lines).

---

Nitpick comments:
In `@src/backend/tests/unit/components/languagemodels/test_minimax.py`:
- Around line 25-28: The test is brittle because it reconstructs a Component
from the private MiniMaxModelComponent._code; instead, obtain the component's
public frontend node/template and pass that to build_custom_component_template.
Replace use of Component(_code=component._code) with the component's public API
(e.g., component.frontend_node or
component.build_frontend_node()/to_frontend_node()) and call
build_custom_component_template(frontend_node) using that value so the test
exercises the same frontend contract as the UI (references:
MiniMaxModelComponent, Component, build_custom_component_template,
frontend_node).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f5ee8c7a-396d-4151-90c8-5049a5ae6536

📥 Commits

Reviewing files that changed from the base of the PR and between 1e61ac4 and 9de0de0.

📒 Files selected for processing (36)
  • src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json
  • src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json
  • src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json
  • src/backend/base/langflow/initial_setup/starter_projects/Custom Component Generator.json
  • src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json
  • src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json
  • src/backend/base/langflow/initial_setup/starter_projects/Hybrid Search RAG.json
  • src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json
  • src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json
  • src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json
  • src/backend/base/langflow/initial_setup/starter_projects/Market Research.json
  • src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json
  • src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json
  • src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json
  • src/backend/base/langflow/initial_setup/starter_projects/Nvidia Remix.json
  • src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json
  • src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json
  • src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json
  • src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json
  • src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json
  • src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json
  • src/backend/base/langflow/initial_setup/starter_projects/Search agent.json
  • src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json
  • src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json
  • src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json
  • src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json
  • src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json
  • src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json
  • src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json
  • src/backend/tests/unit/components/languagemodels/test_minimax.py
  • src/frontend/src/icons/MiniMax/MiniMaxIcon.jsx
  • src/frontend/src/icons/MiniMax/index.tsx
  • src/frontend/src/icons/lazyIconImports.ts
  • src/lfx/src/lfx/components/__init__.py
  • src/lfx/src/lfx/components/minimax/__init__.py
  • src/lfx/src/lfx/components/minimax/minimax.py

"title_case": false,
"type": "code",
"value": "from lfx.custom.custom_component.component import Component\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, HandleInput, MessageTextInput, MultilineInput, TabInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.template.field.base import Output\n\n\nclass ParserComponent(Component):\n display_name = \"Parser\"\n description = \"Extracts text using a template.\"\n documentation: str = \"https://docs.langflow.org/parser\"\n icon = \"braces\"\n\n inputs = [\n HandleInput(\n name=\"input_data\",\n display_name=\"JSON or Table\",\n input_types=[\"DataFrame\", \"Table\", \"Data\", \"JSON\"],\n info=\"Accepts either a DataFrame or a Data object.\",\n required=True,\n ),\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Parser\", \"Stringify\"],\n value=\"Parser\",\n info=\"Convert into raw string instead of using a template.\",\n real_time_refresh=True,\n ),\n MultilineInput(\n name=\"pattern\",\n display_name=\"Template\",\n info=(\n \"Use variables within curly brackets to extract column values for DataFrames \"\n \"or key values for Data.\"\n \"For example: `Name: {Name}, Age: {Age}, Country: {Country}`\"\n ),\n value=\"Text: {text}\", # Example default\n dynamic=True,\n show=True,\n required=True,\n ),\n MessageTextInput(\n name=\"sep\",\n display_name=\"Separator\",\n advanced=True,\n value=\"\\n\",\n info=\"String used to separate rows/items.\",\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Parsed Text\",\n name=\"parsed_text\",\n info=\"Formatted text output.\",\n method=\"parse_combined_text\",\n ),\n ]\n\n def update_build_config(self, build_config, field_value, field_name=None):\n \"\"\"Dynamically hide/show `template` and enforce requirement based on `stringify`.\"\"\"\n if field_name == \"mode\":\n build_config[\"pattern\"][\"show\"] = self.mode == \"Parser\"\n build_config[\"pattern\"][\"required\"] = self.mode == \"Parser\"\n if field_value:\n clean_data = BoolInput(\n name=\"clean_data\",\n display_name=\"Clean Data\",\n info=(\n \"Enable to clean the data by removing empty rows and lines \"\n \"in each cell of the DataFrame/ Data object.\"\n ),\n value=True,\n advanced=True,\n required=False,\n )\n build_config[\"clean_data\"] = clean_data.to_dict()\n else:\n build_config.pop(\"clean_data\", None)\n\n return build_config\n\n def _clean_args(self):\n \"\"\"Prepare arguments based on input type.\"\"\"\n input_data = self.input_data\n\n match input_data:\n case list() if all(isinstance(item, Data) for item in input_data):\n msg = \"List of Data objects is not supported.\"\n raise ValueError(msg)\n case DataFrame():\n return input_data, None\n case Data():\n return None, input_data\n case dict() if \"data\" in input_data:\n try:\n if \"columns\" in input_data: # Likely a DataFrame\n return DataFrame.from_dict(input_data), None\n # Likely a Data object\n return None, Data(**input_data)\n except (TypeError, ValueError, KeyError) as e:\n msg = f\"Invalid structured input provided: {e!s}\"\n raise ValueError(msg) from e\n case _:\n msg = f\"Unsupported input type: {type(input_data)}. Expected DataFrame or Data.\"\n raise ValueError(msg)\n\n def parse_combined_text(self) -> Message:\n \"\"\"Parse all rows/items into a single text or convert input to string if `stringify` is enabled.\"\"\"\n # Early return for stringify option\n if self.mode == \"Stringify\":\n return self.convert_to_string()\n\n df, data = self._clean_args()\n\n lines = []\n if df is not None:\n for _, row in df.iterrows():\n formatted_text = self.pattern.format(**row.to_dict())\n lines.append(formatted_text)\n elif data is not None:\n # Use format_map with a dict that returns default_value for missing keys\n class DefaultDict(dict):\n def __missing__(self, key):\n return data.default_value or \"\"\n\n formatted_text = self.pattern.format_map(DefaultDict(data.data))\n lines.append(formatted_text)\n\n combined_text = self.sep.join(lines)\n self.status = combined_text\n return Message(text=combined_text)\n\n def convert_to_string(self) -> Message:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n result = \"\"\n if isinstance(self.input_data, list):\n result = \"\\n\".join([safe_convert(item, clean_data=self.clean_data or False) for item in self.input_data])\n else:\n result = safe_convert(self.input_data or False)\n self.log(f\"Converted to string with length: {len(result)}\")\n\n message = Message(text=result)\n self.status = message\n return message\n"
"value": "from lfx.custom.custom_component.component import Component\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, HandleInput, MessageTextInput, MultilineInput, TabInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.template.field.base import Output\n\n\nclass ParserComponent(Component):\n display_name = \"Parser\"\n description = \"Extracts text using a template.\"\n documentation: str = \"https://docs.langflow.org/parser\"\n icon = \"braces\"\n\n inputs = [\n HandleInput(\n name=\"input_data\",\n display_name=\"Data or DataFrame\",\n input_types=[\"DataFrame\", \"Data\"],\n info=\"Accepts either a DataFrame or a Data object.\",\n required=True,\n ),\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Parser\", \"Stringify\"],\n value=\"Parser\",\n info=\"Convert into raw string instead of using a template.\",\n real_time_refresh=True,\n ),\n MultilineInput(\n name=\"pattern\",\n display_name=\"Template\",\n info=(\n \"Use variables within curly brackets to extract column values for DataFrames \"\n \"or key values for Data.\"\n \"For example: `Name: {Name}, Age: {Age}, Country: {Country}`\"\n ),\n value=\"Text: {text}\", # Example default\n dynamic=True,\n show=True,\n required=True,\n ),\n MessageTextInput(\n name=\"sep\",\n display_name=\"Separator\",\n advanced=True,\n value=\"\\n\",\n info=\"String used to separate rows/items.\",\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Parsed Text\",\n name=\"parsed_text\",\n info=\"Formatted text output.\",\n method=\"parse_combined_text\",\n ),\n ]\n\n def update_build_config(self, build_config, field_value, field_name=None):\n \"\"\"Dynamically hide/show `template` and enforce requirement based on `stringify`.\"\"\"\n if field_name == \"mode\":\n build_config[\"pattern\"][\"show\"] = self.mode == \"Parser\"\n build_config[\"pattern\"][\"required\"] = self.mode == \"Parser\"\n if field_value:\n clean_data = BoolInput(\n name=\"clean_data\",\n display_name=\"Clean Data\",\n info=(\n \"Enable to clean the data by removing empty rows and lines \"\n \"in each cell of the DataFrame/ Data object.\"\n ),\n value=True,\n advanced=True,\n required=False,\n )\n build_config[\"clean_data\"] = clean_data.to_dict()\n else:\n build_config.pop(\"clean_data\", None)\n\n return build_config\n\n def _clean_args(self):\n \"\"\"Prepare arguments based on input type.\"\"\"\n input_data = self.input_data\n\n match input_data:\n case list() if all(isinstance(item, Data) for item in input_data):\n msg = \"List of Data objects is not supported.\"\n raise ValueError(msg)\n case DataFrame():\n return input_data, None\n case Data():\n return None, input_data\n case dict() if \"data\" in input_data:\n try:\n if \"columns\" in input_data: # Likely a DataFrame\n return DataFrame.from_dict(input_data), None\n # Likely a Data object\n return None, Data(**input_data)\n except (TypeError, ValueError, KeyError) as e:\n msg = f\"Invalid structured input provided: {e!s}\"\n raise ValueError(msg) from e\n case _:\n msg = f\"Unsupported input type: {type(input_data)}. Expected DataFrame or Data.\"\n raise ValueError(msg)\n\n def parse_combined_text(self) -> Message:\n \"\"\"Parse all rows/items into a single text or convert input to string if `stringify` is enabled.\"\"\"\n # Early return for stringify option\n if self.mode == \"Stringify\":\n return self.convert_to_string()\n\n df, data = self._clean_args()\n\n lines = []\n if df is not None:\n for _, row in df.iterrows():\n formatted_text = self.pattern.format(**row.to_dict())\n lines.append(formatted_text)\n elif data is not None:\n # Use format_map with a dict that returns default_value for missing keys\n class DefaultDict(dict):\n def __missing__(self, key):\n return data.default_value or \"\"\n\n formatted_text = self.pattern.format_map(DefaultDict(data.data))\n lines.append(formatted_text)\n\n combined_text = self.sep.join(lines)\n self.status = combined_text\n return Message(text=combined_text)\n\n def convert_to_string(self) -> Message:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n result = \"\"\n if isinstance(self.input_data, list):\n result = \"\\n\".join([safe_convert(item, clean_data=self.clean_data or False) for item in self.input_data])\n else:\n result = safe_convert(self.input_data or False)\n self.log(f\"Converted to string with length: {len(result)}\")\n\n message = Message(text=result)\n self.status = message\n return message\n"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== DataFrame implementation =="
fd -i 'dataframe.py' | xargs -r rg -n -C3 'class\s+DataFrame\b|__bool__|__nonzero__|pandas|pd\.DataFrame'

echo
echo "== Embedded/source Parser convert_to_string implementations =="
rg -n -C4 'def convert_to_string|safe_convert\(self\.input_data.*False|clean_data=self\.clean_data' --glob '*.py' --glob '*.json'

Repository: langflow-ai/langflow

Length of output: 50379


Fix boolean-coercion logic in convert_to_string() method.

Line 143 uses safe_convert(self.input_data or False), which evaluates truthiness of self.input_data before conversion. This breaks Stringify mode for valid DataFrame-like inputs. Additionally, the dynamic clean_data field access uses self.clean_data or False instead of proper attribute checking.

The codebase already contains the correct pattern in ChatOutput (src/lfx/src/lfx/components/input_output/chat_output.py), which uses getattr(self, "clean_data", False) and passes the original object directly to safe_convert without boolean coercion.

Update the source ParserComponent and regenerate the starter JSON:

Suggested fix
 def convert_to_string(self) -> Message:
     """Convert input data to string with proper error handling."""
     result = ""
+    clean_data = getattr(self, "clean_data", False)
     if isinstance(self.input_data, list):
-        result = "\n".join([safe_convert(item, clean_data=self.clean_data or False) for item in self.input_data])
+        result = "\n".join([safe_convert(item, clean_data=clean_data) for item in self.input_data])
     else:
-        result = safe_convert(self.input_data or False)
+        result = safe_convert(self.input_data, clean_data=clean_data)
📝 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.

Suggested change
"value": "from lfx.custom.custom_component.component import Component\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, HandleInput, MessageTextInput, MultilineInput, TabInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.template.field.base import Output\n\n\nclass ParserComponent(Component):\n display_name = \"Parser\"\n description = \"Extracts text using a template.\"\n documentation: str = \"https://docs.langflow.org/parser\"\n icon = \"braces\"\n\n inputs = [\n HandleInput(\n name=\"input_data\",\n display_name=\"Data or DataFrame\",\n input_types=[\"DataFrame\", \"Data\"],\n info=\"Accepts either a DataFrame or a Data object.\",\n required=True,\n ),\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Parser\", \"Stringify\"],\n value=\"Parser\",\n info=\"Convert into raw string instead of using a template.\",\n real_time_refresh=True,\n ),\n MultilineInput(\n name=\"pattern\",\n display_name=\"Template\",\n info=(\n \"Use variables within curly brackets to extract column values for DataFrames \"\n \"or key values for Data.\"\n \"For example: `Name: {Name}, Age: {Age}, Country: {Country}`\"\n ),\n value=\"Text: {text}\", # Example default\n dynamic=True,\n show=True,\n required=True,\n ),\n MessageTextInput(\n name=\"sep\",\n display_name=\"Separator\",\n advanced=True,\n value=\"\\n\",\n info=\"String used to separate rows/items.\",\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Parsed Text\",\n name=\"parsed_text\",\n info=\"Formatted text output.\",\n method=\"parse_combined_text\",\n ),\n ]\n\n def update_build_config(self, build_config, field_value, field_name=None):\n \"\"\"Dynamically hide/show `template` and enforce requirement based on `stringify`.\"\"\"\n if field_name == \"mode\":\n build_config[\"pattern\"][\"show\"] = self.mode == \"Parser\"\n build_config[\"pattern\"][\"required\"] = self.mode == \"Parser\"\n if field_value:\n clean_data = BoolInput(\n name=\"clean_data\",\n display_name=\"Clean Data\",\n info=(\n \"Enable to clean the data by removing empty rows and lines \"\n \"in each cell of the DataFrame/ Data object.\"\n ),\n value=True,\n advanced=True,\n required=False,\n )\n build_config[\"clean_data\"] = clean_data.to_dict()\n else:\n build_config.pop(\"clean_data\", None)\n\n return build_config\n\n def _clean_args(self):\n \"\"\"Prepare arguments based on input type.\"\"\"\n input_data = self.input_data\n\n match input_data:\n case list() if all(isinstance(item, Data) for item in input_data):\n msg = \"List of Data objects is not supported.\"\n raise ValueError(msg)\n case DataFrame():\n return input_data, None\n case Data():\n return None, input_data\n case dict() if \"data\" in input_data:\n try:\n if \"columns\" in input_data: # Likely a DataFrame\n return DataFrame.from_dict(input_data), None\n # Likely a Data object\n return None, Data(**input_data)\n except (TypeError, ValueError, KeyError) as e:\n msg = f\"Invalid structured input provided: {e!s}\"\n raise ValueError(msg) from e\n case _:\n msg = f\"Unsupported input type: {type(input_data)}. Expected DataFrame or Data.\"\n raise ValueError(msg)\n\n def parse_combined_text(self) -> Message:\n \"\"\"Parse all rows/items into a single text or convert input to string if `stringify` is enabled.\"\"\"\n # Early return for stringify option\n if self.mode == \"Stringify\":\n return self.convert_to_string()\n\n df, data = self._clean_args()\n\n lines = []\n if df is not None:\n for _, row in df.iterrows():\n formatted_text = self.pattern.format(**row.to_dict())\n lines.append(formatted_text)\n elif data is not None:\n # Use format_map with a dict that returns default_value for missing keys\n class DefaultDict(dict):\n def __missing__(self, key):\n return data.default_value or \"\"\n\n formatted_text = self.pattern.format_map(DefaultDict(data.data))\n lines.append(formatted_text)\n\n combined_text = self.sep.join(lines)\n self.status = combined_text\n return Message(text=combined_text)\n\n def convert_to_string(self) -> Message:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n result = \"\"\n if isinstance(self.input_data, list):\n result = \"\\n\".join([safe_convert(item, clean_data=self.clean_data or False) for item in self.input_data])\n else:\n result = safe_convert(self.input_data or False)\n self.log(f\"Converted to string with length: {len(result)}\")\n\n message = Message(text=result)\n self.status = message\n return message\n"
def convert_to_string(self) -> Message:
"""Convert input data to string with proper error handling."""
result = ""
clean_data = getattr(self, "clean_data", False)
if isinstance(self.input_data, list):
result = "\n".join([safe_convert(item, clean_data=clean_data) for item in self.input_data])
else:
result = safe_convert(self.input_data, clean_data=clean_data)
self.log(f"Converted to string with length: {len(result)}")
message = Message(text=result)
self.status = message
return message
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Financial` Report
Parser.json at line 1442, The convert_to_string method wrongly coerces inputs
with "or False" and uses self.clean_data or False; update both usages to pass
the original object and use getattr to read the optional clean_data attribute:
in convert_to_string replace safe_convert(item, clean_data=self.clean_data or
False) with safe_convert(item, clean_data=getattr(self, "clean_data", False))
and replace safe_convert(self.input_data or False) with
safe_convert(self.input_data, clean_data=getattr(self, "clean_data", False));
ensure Message creation and self.status assignment remain the same.

Comment on lines +1755 to +1762
"display_name": "Dataframe",
"group_outputs": false,
"method": "retrieve_messages_dataframe",
"name": "dataframe",
"selected": "Table",
"selected": "DataFrame",
"tool_mode": true,
"types": [
"Table"
"DataFrame"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use DataFrame consistently in the Memory output label.

The type metadata was migrated to DataFrame, but the visible label is still Dataframe here and in the embedded component definition. That leaves the starter flow with a stale UI string after the rename.

Suggested fix
-                "display_name": "Dataframe",
+                "display_name": "DataFrame",
-        Output(display_name="Dataframe", name="dataframe", method="retrieve_messages_dataframe", dynamic=True),
+        Output(display_name="DataFrame", name="dataframe", method="retrieve_messages_dataframe", dynamic=True),

Also applies to: 1786-1786

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Meeting`
Summary.json around lines 1755 - 1762, The visible Memory output label
"display_name": "Dataframe" is inconsistent with the migrated type "DataFrame";
update the display_name (and any embedded component definition labels) to
"DataFrame" so the UI matches the metadata (look for entries with name:
"dataframe", method: "retrieve_messages_dataframe", selected: "DataFrame" and
change display_name from "Dataframe" to "DataFrame", also apply the same change
at the other occurrence around the embedded component definition referenced in
the diff).

Comment on lines +960 to +967
"display_name": "Dataframe",
"group_outputs": false,
"method": "retrieve_messages_dataframe",
"name": "dataframe",
"selected": "Table",
"selected": "DataFrame",
"tool_mode": true,
"types": [
"Table"
"DataFrame"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use DataFrame consistently for the Message History output label.

The output is now typed/selected as DataFrame, but the visible label is still Dataframe here and in the embedded component code. That leaves the starter-project UI inconsistent with the rest of the rename.

Also applies to: 992-992

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Memory` Chatbot.json
around lines 960 - 967, Replace the inconsistent lowercase label "Dataframe"
with the canonical "DataFrame" wherever the Message History output is defined
(e.g., the JSON property "display_name": "Dataframe" in the starter project and
any embedded component definitions tied to the node with "method":
"retrieve_messages_dataframe" and "name": "dataframe"); ensure the visible label
matches the "selected": "DataFrame" value and update the other occurrence noted
near the embedded component so both places use "DataFrame" exactly.

"sourceHandle": "{\"dataType\": \"LanguageModelComponent\", \"id\": \"LanguageModelComponent-zY7m0\", \"name\": \"text_output\", \"output_types\": [\"Message\"]}",
"target": "ChatOutput-S7Bzs",
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-S7Bzsœ, œinputTypesœ: [œDataœ, œJSONœ, œDataFrameœ, œTableœ, œMessageœ], œtypeœ: œstrœ}"
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-S7Bzsœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix malformed serialized targetHandle payload.

Line [60] uses non-JSON delimiters (œ...œ) and is inconsistent with other escaped JSON handle payloads in this file. This can break downstream parsing of edge handle metadata.

Proposed fix
-        "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-S7Bzsœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}"
+        "targetHandle": "{\"fieldName\": \"input_value\", \"id\": \"ChatOutput-S7Bzs\", \"inputTypes\": [\"Data\", \"DataFrame\", \"Message\"], \"type\": \"str\"}"
📝 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.

Suggested change
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-S7Bzsœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}"
"targetHandle": "{\"fieldName\": \"input_value\", \"id\": \"ChatOutput-S7Bzs\", \"inputTypes\": [\"Data\", \"DataFrame\", \"Message\"], \"type\": \"str\"}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/SEO` Keyword
Generator.json at line 60, The targetHandle value is malformed using non-JSON
delimiters (œ) which breaks downstream parsing; locate the "targetHandle" entry
(contains "ChatOutput-S7Bzs", "œfieldNameœ", "œinput_valueœ") and replace the œ
delimiters with proper JSON-escaped double quotes so the value is a valid JSON
string (matching the other escaped JSON handle payloads in this file),
preserving the same keys ("fieldName", "id", "inputTypes", "type") and array
contents.

"sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-X1iATœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
"target": "ChatOutput-gbqPo",
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-gbqPoœ, œinputTypesœ: [œDataœ, œJSONœ, œDataFrameœ, œTableœ, œMessageœ], œtypeœ: œotherœ}"
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-gbqPoœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Finish the ChatOutput alias migration or keep the legacy aliases for now.

This snapshot now narrows ChatOutput to ["Data", "DataFrame", "Message"], but the same template still serializes the old "JSON" / "Table" aliases elsewhere, e.g. the edge ID at Line 309 and YfinanceComponent.base_classes at Lines 2945-2950. Because starter projects embed component code directly, importing this flow creates a one-off ChatOutput contract that no longer matches the canonical src/lfx/src/lfx/components/input_output/chat_output.py, so rewiring the template can reject components that still advertise the legacy aliases. Please migrate the whole snapshot together or keep both alias sets accepted here for backward compatibility.

Also applies to: 3863-3863

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/initial_setup/starter_projects/Sequential` Tasks
Agents.json at line 314, The ChatOutput alias usage in this snapshot is
inconsistent: the targetHandle and other serialized places (e.g., edge ID and
YfinanceComponent.base_classes) use the new narrowed set
["Data","DataFrame","Message"] while other parts still serialize legacy aliases
("JSON","Table"), causing runtime contract mismatch with
src/lfx/src/lfx/components/input_output/chat_output.py; fix by migrating the
entire snapshot to a consistent alias set or preserve backward compatibility by
including both sets wherever ChatOutput appears (update the "targetHandle"
entries, the edge ids, and YfinanceComponent.base_classes to either the new
canonical aliases or a combined array
["Data","DataFrame","Message","JSON","Table"] so the embedded components match
the canonical ChatOutput contract).

Comment on lines +11 to +255
def test_minimax_initialization():
component = MiniMaxModelComponent()
assert component.display_name == "MiniMax"
assert component.description == "Generate text using MiniMax LLMs."
assert component.icon == "MiniMax"
assert component.name == "MiniMaxModel"


def test_minimax_default_models():
assert "MiniMax-M2.7" in MINIMAX_MODELS
assert "MiniMax-M2.7-highspeed" in MINIMAX_MODELS
assert len(MINIMAX_MODELS) == 2


def test_minimax_template():
component = MiniMaxModelComponent()
comp = Component(_code=component._code)
frontend_node, _ = build_custom_component_template(comp)

assert isinstance(frontend_node, dict)
assert "template" in frontend_node

input_names = [inp["name"] for inp in frontend_node["template"].values() if isinstance(inp, dict)]
expected_inputs = [
"max_tokens",
"model_kwargs",
"json_mode",
"model_name",
"base_url",
"api_key",
"temperature",
"seed",
]
for input_name in expected_inputs:
assert input_name in input_names


@pytest.fixture
def mock_chat_openai(mocker):
return mocker.patch("lfx.components.minimax.minimax.ChatOpenAI")


@pytest.mark.parametrize(
("temperature", "max_tokens"),
[
(0.5, 100),
(1.0, 500),
(0.7, 1000),
],
)
def test_minimax_build_model(mock_chat_openai, temperature, max_tokens):
component = MiniMaxModelComponent()
component.temperature = temperature
component.max_tokens = max_tokens
component.api_key = "test-key"
component.model_name = "MiniMax-M2.7"
component.model_kwargs = {}
component.base_url = "https://api.minimax.io/v1"
component.seed = 1
component.json_mode = False

mock_instance = MagicMock()
mock_chat_openai.return_value = mock_instance

model = component.build_model()

mock_chat_openai.assert_called_once_with(
max_tokens=max_tokens,
model_kwargs={},
model="MiniMax-M2.7",
base_url="https://api.minimax.io/v1",
api_key="test-key",
temperature=temperature,
seed=1,
)
assert model == mock_instance


def test_minimax_build_model_highspeed(mocker):
component = MiniMaxModelComponent()
component.temperature = 1.0
component.max_tokens = 0
component.api_key = "test-key"
component.model_name = "MiniMax-M2.7-highspeed"
component.model_kwargs = {}
component.base_url = "https://api.minimax.io/v1"
component.seed = 42
component.json_mode = False

mock_chat_openai = mocker.patch("lfx.components.minimax.minimax.ChatOpenAI", return_value=MagicMock())
component.build_model()
mock_chat_openai.assert_called_once_with(
max_tokens=None,
model_kwargs={},
model="MiniMax-M2.7-highspeed",
base_url="https://api.minimax.io/v1",
api_key="test-key",
temperature=1.0,
seed=42,
)


def test_minimax_temperature_zero_becomes_one(mocker):
"""MiniMax requires temperature in (0.0, 1.0], so 0 should become 1.0."""
component = MiniMaxModelComponent()
component.temperature = 0
component.max_tokens = 100
component.api_key = "test-key"
component.model_name = "MiniMax-M2.7"
component.model_kwargs = {}
component.base_url = "https://api.minimax.io/v1"
component.seed = 1
component.json_mode = False

mock_chat_openai = mocker.patch("lfx.components.minimax.minimax.ChatOpenAI", return_value=MagicMock())
component.build_model()
call_kwargs = mock_chat_openai.call_args[1]
assert call_kwargs["temperature"] == 1.0


def test_minimax_temperature_none_becomes_one(mocker):
"""MiniMax requires temperature in (0.0, 1.0], so None should become 1.0."""
component = MiniMaxModelComponent()
component.temperature = None
component.max_tokens = 100
component.api_key = "test-key"
component.model_name = "MiniMax-M2.7"
component.model_kwargs = {}
component.base_url = "https://api.minimax.io/v1"
component.seed = 1
component.json_mode = False

mock_chat_openai = mocker.patch("lfx.components.minimax.minimax.ChatOpenAI", return_value=MagicMock())
component.build_model()
call_kwargs = mock_chat_openai.call_args[1]
assert call_kwargs["temperature"] == 1.0


def test_minimax_default_base_url_when_empty(mocker):
"""When base_url is empty, should default to https://api.minimax.io/v1."""
component = MiniMaxModelComponent()
component.temperature = 1.0
component.max_tokens = 100
component.api_key = "test-key"
component.model_name = "MiniMax-M2.7"
component.model_kwargs = {}
component.base_url = ""
component.seed = 1
component.json_mode = False

mock_chat_openai = mocker.patch("lfx.components.minimax.minimax.ChatOpenAI", return_value=MagicMock())
component.build_model()
call_kwargs = mock_chat_openai.call_args[1]
assert call_kwargs["base_url"] == "https://api.minimax.io/v1"


def test_minimax_json_mode(mocker):
component = MiniMaxModelComponent()
component.api_key = "test-key"
component.json_mode = True
component.temperature = 0.7
component.max_tokens = 100
component.model_name = "MiniMax-M2.7"
component.model_kwargs = {}
component.base_url = "https://api.minimax.io/v1"
component.seed = 1

mock_instance = MagicMock()
mock_bound_instance = MagicMock()
mock_instance.bind.return_value = mock_bound_instance
mocker.patch("lfx.components.minimax.minimax.ChatOpenAI", return_value=mock_instance)

model = component.build_model()
mock_instance.bind.assert_called_once_with(response_format={"type": "json_object"})
assert model == mock_bound_instance


def test_minimax_get_models_no_api_key():
component = MiniMaxModelComponent()
component.api_key = None
models = component.get_models()
assert models == MINIMAX_MODELS


def test_minimax_get_models(mocker):
component = MiniMaxModelComponent()
mock_get = mocker.patch("requests.get")
mock_response = MagicMock()
mock_response.json.return_value = {
"data": [
{"id": "MiniMax-M2.7"},
{"id": "MiniMax-M2.7-highspeed"},
]
}
mock_get.return_value = mock_response

component.api_key = "test-key"
component.base_url = "https://api.minimax.io/v1"
models = component.get_models()
assert models == ["MiniMax-M2.7", "MiniMax-M2.7-highspeed"]
mock_get.assert_called_once_with(
"https://api.minimax.io/v1/models",
headers={"Authorization": "Bearer test-key", "Accept": "application/json"},
timeout=10,
)


def test_minimax_get_models_request_error(mocker):
import requests as req

component = MiniMaxModelComponent()
component.api_key = "test-key"
component.base_url = "https://api.minimax.io/v1"

mocker.patch("requests.get", side_effect=req.RequestException("Connection error"))
models = component.get_models()
assert models == MINIMAX_MODELS


def test_minimax_update_build_config():
component = MiniMaxModelComponent()
build_config = {"model_name": {"options": []}}

updated = component.update_build_config(build_config, "test-key", "api_key")
assert "model_name" in updated

updated = component.update_build_config(build_config, "MiniMax-M2.7", "model_name")
assert "model_name" in updated


def test_minimax_error_handling(mock_chat_openai):
component = MiniMaxModelComponent()
component.api_key = "invalid-key"
component.model_name = "MiniMax-M2.7"
component.temperature = 1.0
component.max_tokens = 100
component.model_kwargs = {}
component.base_url = "https://api.minimax.io/v1"
component.seed = 1
component.json_mode = False

mock_chat_openai.side_effect = Exception("Invalid API key")

with pytest.raises(Exception, match="Invalid API key"):
component.build_model()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Move this suite onto ComponentTestBaseWithoutClient.

These backend component tests are written as ad-hoc pytest functions, so they skip the repo’s required component_class, default_kwargs, and file_names_mapping fixtures and miss the standard version/backward-compat checks that come with the component test harness. As per coding guidelines, src/backend/tests/unit/components/**/*.py tests should inherit from the appropriate ComponentTestBase family and provide component_class, default_kwargs, and file_names_mapping fixtures.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/tests/unit/components/languagemodels/test_minimax.py` around
lines 11 - 255, The test suite should be converted to use the standard component
test harness by creating a test class that inherits from
ComponentTestBaseWithoutClient and providing the required fixtures:
component_class (pointing to MiniMaxModelComponent), default_kwargs (a dict with
minimal valid kwargs like api_key, model_name, base_url, etc.), and
file_names_mapping (as required by the harness). Move the existing standalone
pytest functions into methods on that class (or keep them as module-level tests
that reuse the provided fixtures) and update any direct construction of
MiniMaxModelComponent() to rely on the component_class/default_kwargs fixtures
where appropriate; keep special-case tests (like get_models HTTP mocks,
json_mode, and error handling) but adapt them to use the harness fixtures and
ensure names reference MiniMaxModelComponent, build_model, get_models,
update_build_config, and MINIMAX_MODELS so the harness runs the standard
version/backward-compat checks.

Comment on lines +230 to +238
def test_minimax_update_build_config():
component = MiniMaxModelComponent()
build_config = {"model_name": {"options": []}}

updated = component.update_build_config(build_config, "test-key", "api_key")
assert "model_name" in updated

updated = component.update_build_config(build_config, "MiniMax-M2.7", "model_name")
assert "model_name" in updated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

test_minimax_update_build_config isn't asserting any behavior.

"model_name" already exists in build_config, so both assertions still pass if update_build_config() is a no-op. Build the config from to_frontend_node() and assert the expected option/value changes instead. As per coding guidelines, component build-config tests should call to_frontend_node() to get the node template and then verify the mutations made by update_build_config().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/tests/unit/components/languagemodels/test_minimax.py` around
lines 230 - 238, Replace the no-op assertions in
test_minimax_update_build_config with assertions that verify real mutations:
instantiate MiniMaxModelComponent, call its to_frontend_node() to obtain the
initial build_config/node template, then call
component.update_build_config(build_config, "test-key", "api_key") and assert
the specific option/value changes inside the returned config (e.g., that the
"api_key" option exists/was added under the correct model key and contains
"test-key"); repeat similarly for update_build_config(build_config,
"MiniMax-M2.7", "model_name") and assert the model_name option was set/updated
to "MiniMax-M2.7". Ensure you reference MiniMaxModelComponent,
to_frontend_node(), and update_build_config() when locating where to change the
test.

height="90"
rx="18"
ry="18"
fill={props.isDark ? "#1a1a2e" : "#1a1a2e"}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

isDark branch currently does not switch theme colors.

The fill color uses the same value for both modes, so dark-mode support is effectively inactive.

🎨 Suggested fix
-      fill={props.isDark ? "#1a1a2e" : "#1a1a2e"}
+      fill={props.isDark ? "#1a1a2e" : "#f3f4f6"}
...
-      fill="#ffffff"
+      fill={props.isDark ? "#ffffff" : "#1a1a2e"}

As per coding guidelines: "In SVG components, use the isDark prop to switch between light and dark color schemes (e.g., fill={props.isDark ? "#ffffff" : "#0A0A0A"})."

Also applies to: 25-25

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/frontend/src/icons/MiniMax/MiniMaxIcon.jsx` at line 16, The SVG fill uses
the same color for both branches so dark mode never changes; update the
conditional in the MiniMaxIcon component (where it uses props.isDark) to choose
different colors for dark vs light (for example fill={props.isDark ? "#ffffff" :
"#0A0A0A"}), and apply the same fix to the second occurrence referenced (the
other fill at the same component), ensuring both places use distinct dark and
light hex values or design tokens.

Comment on lines +91 to +108
def get_models(self) -> list[str]:
"""Return the list of available MiniMax models."""
if not self.api_key:
return MINIMAX_MODELS

base_url = self.base_url or "https://api.minimax.io/v1"
url = f"{base_url}/models"
headers = {"Authorization": f"Bearer {self.api_key}", "Accept": "application/json"}

try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
models = [model["id"] for model in data.get("data", [])]
return models if models else MINIMAX_MODELS
except requests.RequestException as e:
self.status = f"Error fetching models: {e}"
return MINIMAX_MODELS
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

python - <<'PY'
from pydantic.v1 import SecretStr

secret = SecretStr("sk-test-123")
print("masked_header:", f"Bearer {secret}")
print("raw_header:   ", f"Bearer {secret.get_secret_value()}")
PY

echo
echo "MiniMax implementation:"
sed -n '91,142p' src/lfx/src/lfx/components/minimax/minimax.py

echo
echo "Existing OpenAI sibling pattern:"
sed -n '91,140p' src/lfx/src/lfx/components/openai/openai.py

Repository: langflow-ai/langflow

Length of output: 2687


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the class definition and field types
echo "=== MiniMax Component Class Definition ==="
head -n 90 src/lfx/src/lfx/components/minimax/minimax.py | tail -n 40

echo
echo "=== Full MiniMax Component (first 150 lines) ==="
head -n 150 src/lfx/src/lfx/components/minimax/minimax.py

echo
echo "=== Check imports in minimax.py ==="
head -n 20 src/lfx/src/lfx/components/minimax/minimax.py

Repository: langflow-ai/langflow

Length of output: 7031


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check if api_key is inherited and what type it is
echo "=== Base class LCModelComponent to understand api_key type ==="
fd -t f "model.py" src/lfx/src/lfx/base/ 2>/dev/null | head -5 | xargs ls -la

# Search for api_key field definition in base class
rg -A 3 "api_key.*:" src/lfx/src/lfx/base/ --max-count=10

echo
echo "=== Check OpenAI get_models() implementation ==="
sed -n '50,120p' src/lfx/src/lfx/components/openai/openai.py | grep -A 20 "def get_models"

Repository: langflow-ai/langflow

Length of output: 10824


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check for Ruff TRY300 warning in the file
echo "=== Check for any Ruff comments or issues around lines 100-108 ==="
sed -n '95,110p' src/lfx/src/lfx/components/minimax/minimax.py

# Also check if there's a pyproject.toml or ruff config
echo
echo "=== Ruff configuration ==="
rg "TRY300\|bare-except" . --max-count=5 2>/dev/null || echo "No TRY300 references found"

Repository: langflow-ai/langflow

Length of output: 813


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the complete OpenAI component to check get_models()
echo "=== OpenAI Component get_models() method ==="
rg -A 15 "def get_models" src/lfx/src/lfx/components/openai/openai.py

echo
echo "=== Check if OpenAI wraps api_key in Authorization header ==="
rg -B 5 -A 10 "Authorization.*Bearer" src/lfx/src/lfx/components/openai/openai.py || echo "No Bearer pattern found in OpenAI"

Repository: langflow-ai/langflow

Length of output: 108


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify the exact type returned by get_secret_value()
python - <<'PY'
from pydantic.v1 import SecretStr

# Test what type self.api_key would be
class TestInput:
    def __init__(self):
        self.api_key = SecretStr("sk-test-123")
    
    def test_direct_interpolation(self):
        # This is what minimax.py line 98 does
        header = f"Bearer {self.api_key}"
        return header
    
    def test_unwrapped(self):
        # This is what build_model() does
        api_key = SecretStr(self.api_key).get_secret_value() if self.api_key else None
        header = f"Bearer {api_key}"
        return header

t = TestInput()
print(f"Direct interpolation: {t.test_direct_interpolation()}")
print(f"After unwrap: {t.test_unwrapped()}")
print(f"Type of self.api_key: {type(t.api_key).__name__}")
PY

Repository: langflow-ai/langflow

Length of output: 167


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Test the actual unwrap behavior more carefully
python - <<'PY'
from pydantic.v1 import SecretStr

class TestComponent:
    def __init__(self):
        self.api_key = SecretStr("sk-test-123")
    
    def test_build_model_pattern(self):
        # Mimics build_model() at line 126-127
        api_key = self.api_key
        api_key = SecretStr(api_key).get_secret_value() if api_key else None
        return api_key

t = TestComponent()
result = t.test_build_model_pattern()
print(f"Result from build_model pattern: {result}")
print(f"Type: {type(result).__name__}")

# Now test in a header
header = f"Bearer {result}"
print(f"Header with result: {header}")

# Test direct get_secret_value()
header2 = f"Bearer {t.api_key.get_secret_value()}"
print(f"Header with get_secret_value(): {header2}")
PY

Repository: langflow-ai/langflow

Length of output: 212


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check if there's a parent class with api_key field definition
echo "=== Check LCModelComponent base class ==="
cat src/lfx/src/lfx/base/models/model.py | head -100

Repository: langflow-ai/langflow

Length of output: 3929


Unwrap the API key before using it in network requests.

get_models() at line 98 interpolates self.api_key directly into the Authorization header. If this field is a Pydantic SecretStr, the string representation is masked, so the request sends Bearer ********** and silently falls back to MINIMAX_MODELS.

Additionally, build_model() at line 127 has a related issue: wrapping an already-SecretStr object in SecretStr() again doesn't unwrap it—SecretStr(api_key).get_secret_value() still returns a masked value. Call .get_secret_value() directly on the instance instead.

🔧 Proposed fix
     def get_models(self) -> list[str]:
         """Return the list of available MiniMax models."""
-        if not self.api_key:
+        api_key_value = self.api_key.get_secret_value() if isinstance(self.api_key, SecretStr) else self.api_key
+        if not api_key_value:
             return MINIMAX_MODELS
 
         base_url = self.base_url or "https://api.minimax.io/v1"
         url = f"{base_url}/models"
-        headers = {"Authorization": f"Bearer {self.api_key}", "Accept": "application/json"}
+        headers = {"Authorization": f"Bearer {api_key_value}", "Accept": "application/json"}
 
         try:
             response = requests.get(url, headers=headers, timeout=10)
 
     def build_model(self) -> LanguageModel:
         api_key = self.api_key
-        api_key = SecretStr(api_key).get_secret_value() if api_key else None
+        api_key = api_key.get_secret_value() if isinstance(api_key, SecretStr) else api_key
🧰 Tools
🪛 GitHub Actions: Ruff Style Check

[error] 105-105: ruff check failed (TRY300): Consider moving this statement to an else block.

🪛 GitHub Check: Ruff Style Check (3.13)

[failure] 105-105: Ruff (TRY300)
src/lfx/src/lfx/components/minimax/minimax.py:105:13: TRY300 Consider moving this statement to an else block

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lfx/src/lfx/components/minimax/minimax.py` around lines 91 - 108, The
Authorization header is using a masked SecretStr instead of the real API key; in
get_models (and similarly in build_model) detect if self.api_key is a pydantic
SecretStr and call .get_secret_value() to unwrap it before interpolating into
headers (use isinstance(self.api_key, SecretStr) or similar), do not re-wrap an
already-SecretStr value with SecretStr()—always extract the raw string when
making network requests and then set headers={"Authorization": f"Bearer
{unwrapped_api_key}", ...}; update build_model to also unwrap any provided
api_key parameter via .get_secret_value() if it's a SecretStr.

Comment on lines +100 to +108
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
models = [model["id"] for model in data.get("data", [])]
return models if models else MINIMAX_MODELS
except requests.RequestException as e:
self.status = f"Error fetching models: {e}"
return MINIMAX_MODELS
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix the Ruff TRY300 failure in get_models().

This block currently fails CI. Move the success-path return into an else block to satisfy Ruff without changing behavior.

🧹 Minimal fix
         try:
             response = requests.get(url, headers=headers, timeout=10)
             response.raise_for_status()
             data = response.json()
             models = [model["id"] for model in data.get("data", [])]
-            return models if models else MINIMAX_MODELS
         except requests.RequestException as e:
             self.status = f"Error fetching models: {e}"
             return MINIMAX_MODELS
+        else:
+            return models if models else MINIMAX_MODELS

As per coding guidelines "Format Python code with ruff before linting; run make format_backend first before running lint checks".

📝 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.

Suggested change
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
models = [model["id"] for model in data.get("data", [])]
return models if models else MINIMAX_MODELS
except requests.RequestException as e:
self.status = f"Error fetching models: {e}"
return MINIMAX_MODELS
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
models = [model["id"] for model in data.get("data", [])]
except requests.RequestException as e:
self.status = f"Error fetching models: {e}"
return MINIMAX_MODELS
else:
return models if models else MINIMAX_MODELS
🧰 Tools
🪛 GitHub Actions: Ruff Style Check

[error] 105-105: ruff check failed (TRY300): Consider moving this statement to an else block.

🪛 GitHub Check: Ruff Style Check (3.13)

[failure] 105-105: Ruff (TRY300)
src/lfx/src/lfx/components/minimax/minimax.py:105:13: TRY300 Consider moving this statement to an else block

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lfx/src/lfx/components/minimax/minimax.py` around lines 100 - 108, In
get_models(), Ruff flags TRY300 because the try block contains a return; move
the success-path return out of the try by computing the response, parsing data
and building models inside the try (keeping response.raise_for_status()), then
add an else: block after the except to return models if present or
MINIMAX_MODELS; keep the except handling setting self.status and returning
MINIMAX_MODELS unchanged. Reference: function get_models, MINIMAX_MODELS,
requests.get, requests.RequestException, response.raise_for_status(), data =
response.json().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant