langflow-base-nightly 1.7.0.dev55__py3-none-any.whl → 1.7.0.dev56__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. langflow/initial_setup/starter_projects/Basic Prompt Chaining.json +31 -1088
  2. langflow/initial_setup/starter_projects/Basic Prompting.json +196 -135
  3. langflow/initial_setup/starter_projects/Blog Writer.json +141 -84
  4. langflow/initial_setup/starter_projects/Custom Component Generator.json +133 -73
  5. langflow/initial_setup/starter_projects/Document Q&A.json +136 -81
  6. langflow/initial_setup/starter_projects/Financial Report Parser.json +12 -365
  7. langflow/initial_setup/starter_projects/Hybrid Search RAG.json +19 -729
  8. langflow/initial_setup/starter_projects/Image Sentiment Analysis.json +688 -733
  9. langflow/initial_setup/starter_projects/Instagram Copywriter.json +322 -203
  10. langflow/initial_setup/starter_projects/Invoice Summarizer.json +47 -21
  11. langflow/initial_setup/starter_projects/Market Research.json +63 -394
  12. langflow/initial_setup/starter_projects/Meeting Summary.json +266 -168
  13. langflow/initial_setup/starter_projects/Memory Chatbot.json +136 -81
  14. langflow/initial_setup/starter_projects/News Aggregator.json +49 -24
  15. langflow/initial_setup/starter_projects/Nvidia Remix.json +48 -23
  16. langflow/initial_setup/starter_projects/Pok/303/251dex Agent.json" +49 -23
  17. langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json +113 -418
  18. langflow/initial_setup/starter_projects/Price Deal Finder.json +48 -22
  19. langflow/initial_setup/starter_projects/Research Agent.json +319 -181
  20. langflow/initial_setup/starter_projects/Research Translation Loop.json +636 -615
  21. langflow/initial_setup/starter_projects/SEO Keyword Generator.json +145 -89
  22. langflow/initial_setup/starter_projects/SaaS Pricing.json +48 -22
  23. langflow/initial_setup/starter_projects/Search agent.json +47 -21
  24. langflow/initial_setup/starter_projects/Sequential Tasks Agents.json +147 -54
  25. langflow/initial_setup/starter_projects/Simple Agent.json +47 -16
  26. langflow/initial_setup/starter_projects/Social Media Agent.json +47 -16
  27. langflow/initial_setup/starter_projects/Text Sentiment Analysis.json +398 -251
  28. langflow/initial_setup/starter_projects/Travel Planning Agents.json +146 -53
  29. langflow/initial_setup/starter_projects/Twitter Thread Generator.json +137 -81
  30. langflow/initial_setup/starter_projects/Vector Store RAG.json +133 -82
  31. langflow/initial_setup/starter_projects/Youtube Analysis.json +182 -106
  32. langflow/services/storage/local.py +13 -8
  33. langflow/services/storage/s3.py +0 -6
  34. {langflow_base_nightly-1.7.0.dev55.dist-info → langflow_base_nightly-1.7.0.dev56.dist-info}/METADATA +2 -2
  35. {langflow_base_nightly-1.7.0.dev55.dist-info → langflow_base_nightly-1.7.0.dev56.dist-info}/RECORD +37 -37
  36. {langflow_base_nightly-1.7.0.dev55.dist-info → langflow_base_nightly-1.7.0.dev56.dist-info}/WHEEL +0 -0
  37. {langflow_base_nightly-1.7.0.dev55.dist-info → langflow_base_nightly-1.7.0.dev56.dist-info}/entry_points.txt +0 -0
@@ -7,7 +7,7 @@
7
7
  "data": {
8
8
  "sourceHandle": {
9
9
  "dataType": "ChatInput",
10
- "id": "ChatInput-0fTqa",
10
+ "id": "ChatInput-nr0Vp",
11
11
  "name": "message",
12
12
  "output_types": [
13
13
  "Message"
@@ -15,169 +15,159 @@
15
15
  },
16
16
  "targetHandle": {
17
17
  "fieldName": "search_query",
18
- "id": "ArXivComponent-H8Mae",
18
+ "id": "ArXivComponent-tAHR5",
19
19
  "inputTypes": [
20
20
  "Message"
21
21
  ],
22
22
  "type": "str"
23
23
  }
24
24
  },
25
- "id": "reactflow__edge-ChatInput-0fTqa{œdataTypeœ:œChatInputœ,œidœ:œChatInput-0fTqaœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ArXivComponent-H8Mae{œfieldNameœ:œsearch_queryœ,œidœ:œArXivComponent-H8Maeœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
25
+ "id": "reactflow__edge-ChatInput-nr0Vp{œdataTypeœ:œChatInputœ,œidœ:œChatInput-nr0Vpœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ArXivComponent-tAHR5{œfieldNameœ:œsearch_queryœ,œidœ:œArXivComponent-tAHR5œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
26
26
  "selected": false,
27
- "source": "ChatInput-0fTqa",
28
- "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-0fTqaœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
29
- "target": "ArXivComponent-H8Mae",
30
- "targetHandle": "{œfieldNameœ: œsearch_queryœ, œidœ: œArXivComponent-H8Maeœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
27
+ "source": "ChatInput-nr0Vp",
28
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-nr0Vpœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
29
+ "target": "ArXivComponent-tAHR5",
30
+ "targetHandle": "{œfieldNameœ: œsearch_queryœ, œidœ: œArXivComponent-tAHR5œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
31
31
  },
32
32
  {
33
- "animated": false,
34
33
  "className": "",
35
34
  "data": {
36
35
  "sourceHandle": {
37
- "dataType": "ArXivComponent",
38
- "id": "ArXivComponent-H8Mae",
39
- "name": "dataframe",
36
+ "dataType": "LoopComponent",
37
+ "id": "LoopComponent-GtPZT",
38
+ "name": "item",
40
39
  "output_types": [
41
- "DataFrame"
40
+ "Data"
42
41
  ]
43
42
  },
44
43
  "targetHandle": {
45
- "fieldName": "data",
46
- "id": "LoopComponent-qcJgH",
44
+ "fieldName": "input_data",
45
+ "id": "ParserComponent-pXAMb",
47
46
  "inputTypes": [
48
- "DataFrame"
47
+ "DataFrame",
48
+ "Data"
49
49
  ],
50
50
  "type": "other"
51
51
  }
52
52
  },
53
- "id": "reactflow__edge-ArXivComponent-H8Mae{œdataTypeœ:œArXivComponentœ,œidœ:œArXivComponent-H8Maeœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-LoopComponent-qcJgH{œfieldNameœ:œdataœ,œidœ:œLoopComponent-qcJgHœ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}",
54
- "selected": false,
55
- "source": "ArXivComponent-H8Mae",
56
- "sourceHandle": "{œdataTypeœ: œArXivComponentœ, œidœ: œArXivComponent-H8Maeœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}",
57
- "target": "LoopComponent-qcJgH",
58
- "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œLoopComponent-qcJgHœ, œinputTypesœ: [œDataFrameœ], œtypeœ: œotherœ}"
53
+ "id": "xy-edge__LoopComponent-GtPZT{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-GtPZTœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}-ParserComponent-pXAMb{œfieldNameœ:œinput_dataœ,œidœ:œParserComponent-pXAMbœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}",
54
+ "source": "LoopComponent-GtPZT",
55
+ "sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-GtPZTœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}",
56
+ "target": "ParserComponent-pXAMb",
57
+ "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œParserComponent-pXAMbœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}"
59
58
  },
60
59
  {
61
- "animated": false,
62
60
  "className": "",
63
61
  "data": {
64
62
  "sourceHandle": {
65
- "dataType": "LoopComponent",
66
- "id": "LoopComponent-qcJgH",
67
- "name": "item",
63
+ "dataType": "ParserComponent",
64
+ "id": "ParserComponent-pXAMb",
65
+ "name": "parsed_text",
68
66
  "output_types": [
69
- "Data"
67
+ "Message"
70
68
  ]
71
69
  },
72
70
  "targetHandle": {
73
- "fieldName": "input_data",
74
- "id": "ParserComponent-E1d8t",
71
+ "fieldName": "input_value",
72
+ "id": "LanguageModelComponent-XKvly",
75
73
  "inputTypes": [
76
- "DataFrame",
77
- "Data"
74
+ "Message"
78
75
  ],
79
- "type": "other"
76
+ "type": "str"
80
77
  }
81
78
  },
82
- "id": "reactflow__edge-LoopComponent-qcJgH{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-qcJgHœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}-ParserComponent-E1d8t{œfieldNameœ:œinput_dataœ,œidœ:œParserComponent-E1d8tœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}",
83
- "selected": false,
84
- "source": "LoopComponent-qcJgH",
85
- "sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-qcJgHœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}",
86
- "target": "ParserComponent-E1d8t",
87
- "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œParserComponent-E1d8tœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}"
79
+ "id": "xy-edge__ParserComponent-pXAMb{œdataTypeœ:œParserComponentœ,œidœ:œParserComponent-pXAMbœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-XKvly{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-XKvlyœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
80
+ "source": "ParserComponent-pXAMb",
81
+ "sourceHandle": "{œdataTypeœ: œParserComponentœ, œidœ: œParserComponent-pXAMbœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}",
82
+ "target": "LanguageModelComponent-XKvly",
83
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-XKvlyœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
88
84
  },
89
85
  {
90
- "animated": false,
91
86
  "className": "",
92
87
  "data": {
93
88
  "sourceHandle": {
94
- "dataType": "LoopComponent",
95
- "id": "LoopComponent-qcJgH",
96
- "name": "done",
89
+ "dataType": "LanguageModelComponent",
90
+ "id": "LanguageModelComponent-XKvly",
91
+ "name": "text_output",
97
92
  "output_types": [
98
- "DataFrame"
93
+ "Message"
99
94
  ]
100
95
  },
101
96
  "targetHandle": {
102
- "fieldName": "input_value",
103
- "id": "ChatOutput-NVM2L",
104
- "inputTypes": [
97
+ "dataType": "LoopComponent",
98
+ "id": "LoopComponent-GtPZT",
99
+ "name": "item",
100
+ "output_types": [
105
101
  "Data",
106
- "DataFrame",
107
102
  "Message"
108
- ],
109
- "type": "other"
103
+ ]
110
104
  }
111
105
  },
112
- "id": "reactflow__edge-LoopComponent-qcJgH{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-qcJgHœ,œnameœ:œdoneœ,œoutput_typesœ:[œDataFrameœ]}-ChatOutput-NVM2L{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-NVM2Lœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}",
113
- "selected": false,
114
- "source": "LoopComponent-qcJgH",
115
- "sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-qcJgHœ, œnameœ: œdoneœ, œoutput_typesœ: [œDataFrameœ]}",
116
- "target": "ChatOutput-NVM2L",
117
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-NVM2Lœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}"
106
+ "id": "xy-edge__LanguageModelComponent-XKvly{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-XKvlyœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-LoopComponent-GtPZT{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-GtPZTœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ,œMessageœ]}",
107
+ "source": "LanguageModelComponent-XKvly",
108
+ "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-XKvlyœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
109
+ "target": "LoopComponent-GtPZT",
110
+ "targetHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-GtPZTœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ, œMessageœ]}"
118
111
  },
119
112
  {
120
- "animated": false,
121
113
  "className": "",
122
114
  "data": {
123
115
  "sourceHandle": {
124
- "dataType": "ParserComponent",
125
- "id": "ParserComponent-E1d8t",
126
- "name": "parsed_text",
116
+ "dataType": "ArXivComponent",
117
+ "id": "ArXivComponent-tAHR5",
118
+ "name": "dataframe",
127
119
  "output_types": [
128
- "Message"
120
+ "DataFrame"
129
121
  ]
130
122
  },
131
123
  "targetHandle": {
132
- "fieldName": "input_value",
133
- "id": "LanguageModelComponent-khJQA",
124
+ "fieldName": "data",
125
+ "id": "LoopComponent-GtPZT",
134
126
  "inputTypes": [
135
- "Message"
127
+ "DataFrame"
136
128
  ],
137
- "type": "str"
129
+ "type": "other"
138
130
  }
139
131
  },
140
- "id": "xy-edge__ParserComponent-E1d8t{œdataTypeœ:œParserComponentœ,œidœ:œParserComponent-E1d8tœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-khJQA{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-khJQAœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
141
- "selected": false,
142
- "source": "ParserComponent-E1d8t",
143
- "sourceHandle": "{œdataTypeœ: œParserComponentœ, œidœ: œParserComponent-E1d8tœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}",
144
- "target": "LanguageModelComponent-khJQA",
145
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-khJQAœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
132
+ "id": "xy-edge__ArXivComponent-tAHR5{œdataTypeœ:œArXivComponentœ,œidœ:œArXivComponent-tAHR5œ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-LoopComponent-GtPZT{œfieldNameœ:œdataœ,œidœ:œLoopComponent-GtPZTœ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}",
133
+ "source": "ArXivComponent-tAHR5",
134
+ "sourceHandle": "{œdataTypeœ: œArXivComponentœ, œidœ: œArXivComponent-tAHR5œ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}",
135
+ "target": "LoopComponent-GtPZT",
136
+ "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œLoopComponent-GtPZTœ, œinputTypesœ: [œDataFrameœ], œtypeœ: œotherœ}"
146
137
  },
147
138
  {
148
- "animated": false,
149
139
  "className": "",
150
140
  "data": {
151
141
  "sourceHandle": {
152
- "dataType": "LanguageModelComponent",
153
- "id": "LanguageModelComponent-khJQA",
154
- "name": "text_output",
142
+ "dataType": "LoopComponent",
143
+ "id": "LoopComponent-GtPZT",
144
+ "name": "done",
155
145
  "output_types": [
156
- "Message"
146
+ "DataFrame"
157
147
  ]
158
148
  },
159
149
  "targetHandle": {
160
- "dataType": "LoopComponent",
161
- "id": "LoopComponent-qcJgH",
162
- "name": "item",
163
- "output_types": [
150
+ "fieldName": "input_value",
151
+ "id": "ChatOutput-YAED9",
152
+ "inputTypes": [
164
153
  "Data",
154
+ "DataFrame",
165
155
  "Message"
166
- ]
156
+ ],
157
+ "type": "other"
167
158
  }
168
159
  },
169
- "id": "xy-edge__LanguageModelComponent-khJQA{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-khJQAœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-LoopComponent-qcJgH{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-qcJgHœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ,œMessageœ]}",
170
- "selected": false,
171
- "source": "LanguageModelComponent-khJQA",
172
- "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-khJQAœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
173
- "target": "LoopComponent-qcJgH",
174
- "targetHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-qcJgHœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ, œMessageœ]}"
160
+ "id": "xy-edge__LoopComponent-GtPZT{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-GtPZTœ,œnameœ:œdoneœ,œoutput_typesœ:[œDataFrameœ]}-ChatOutput-YAED9{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-YAED9œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}",
161
+ "source": "LoopComponent-GtPZT",
162
+ "sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-GtPZTœ, œnameœ: œdoneœ, œoutput_typesœ: [œDataFrameœ]}",
163
+ "target": "ChatOutput-YAED9",
164
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-YAED9œ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}"
175
165
  }
176
166
  ],
177
167
  "nodes": [
178
168
  {
179
169
  "data": {
180
- "id": "ArXivComponent-H8Mae",
170
+ "id": "ArXivComponent-tAHR5",
181
171
  "node": {
182
172
  "base_classes": [
183
173
  "DataFrame"
@@ -330,7 +320,7 @@
330
320
  "type": "ArXivComponent"
331
321
  },
332
322
  "dragging": false,
333
- "id": "ArXivComponent-H8Mae",
323
+ "id": "ArXivComponent-tAHR5",
334
324
  "measured": {
335
325
  "height": 369,
336
326
  "width": 320
@@ -344,7 +334,7 @@
344
334
  },
345
335
  {
346
336
  "data": {
347
- "id": "ChatOutput-NVM2L",
337
+ "id": "ChatOutput-YAED9",
348
338
  "node": {
349
339
  "base_classes": [
350
340
  "Message"
@@ -613,21 +603,21 @@
613
603
  "type": "ChatOutput"
614
604
  },
615
605
  "dragging": false,
616
- "id": "ChatOutput-NVM2L",
606
+ "id": "ChatOutput-YAED9",
617
607
  "measured": {
618
608
  "height": 48,
619
609
  "width": 192
620
610
  },
621
611
  "position": {
622
- "x": 1078.5167042474975,
623
- "y": 313.63532700509995
612
+ "x": 1161.842067639501,
613
+ "y": 380.6300719873473
624
614
  },
625
615
  "selected": false,
626
616
  "type": "genericNode"
627
617
  },
628
618
  {
629
619
  "data": {
630
- "id": "ChatInput-0fTqa",
620
+ "id": "ChatInput-nr0Vp",
631
621
  "node": {
632
622
  "base_classes": [
633
623
  "Message"
@@ -891,7 +881,7 @@
891
881
  "type": "ChatInput"
892
882
  },
893
883
  "dragging": false,
894
- "id": "ChatInput-0fTqa",
884
+ "id": "ChatInput-nr0Vp",
895
885
  "measured": {
896
886
  "height": 204,
897
887
  "width": 320
@@ -905,7 +895,7 @@
905
895
  },
906
896
  {
907
897
  "data": {
908
- "id": "note-Xz4Fg",
898
+ "id": "note-nrMOM",
909
899
  "node": {
910
900
  "description": "# **Langflow Loop Component Template - ArXiv search result Translator** \nThis template translates research paper summaries on ArXiv into Portuguese and summarizes them. \n Using **Langflow’s looping mechanism**, the template iterates through multiple research papers, translates them with the **OpenAI** model component, and outputs an aggregated version of all translated papers. \n\n## Quickstart \n 1. Add your OpenAI API key to the **Language Model** component. \n2. In the **Playground**, enter a query related to a research topic (for example, “Quantum Computing Advancements”). \n\n The flow fetches a list of research papers from ArXiv matching the query. Each paper in the retrieved list is processed one-by-one using the Langflow **Loop component**. \n\n The abstract of each paper is translated into Portuguese by the **OpenAI** model component. \n\n Once all papers are translated, the system aggregates them into a **single structured output**.",
911
901
  "display_name": "",
@@ -916,7 +906,7 @@
916
906
  },
917
907
  "dragging": false,
918
908
  "height": 647,
919
- "id": "note-Xz4Fg",
909
+ "id": "note-nrMOM",
920
910
  "measured": {
921
911
  "height": 647,
922
912
  "width": 576
@@ -932,30 +922,37 @@
932
922
  },
933
923
  {
934
924
  "data": {
935
- "id": "ParserComponent-E1d8t",
925
+ "id": "LanguageModelComponent-XKvly",
936
926
  "node": {
937
927
  "base_classes": [
928
+ "LanguageModel",
938
929
  "Message"
939
930
  ],
940
931
  "beta": false,
941
932
  "conditional_paths": [],
942
933
  "custom_fields": {},
943
- "description": "Extracts text using a template.",
944
- "display_name": "Parser",
945
- "documentation": "",
934
+ "description": "Runs a language model given a specified provider.",
935
+ "display_name": "Language Model",
936
+ "documentation": "https://docs.langflow.org/components-models",
946
937
  "edited": false,
947
938
  "field_order": [
948
- "input_data",
949
- "mode",
950
- "pattern",
951
- "sep"
939
+ "model",
940
+ "api_key",
941
+ "base_url_ibm_watsonx",
942
+ "project_id",
943
+ "ollama_base_url",
944
+ "input_value",
945
+ "system_message",
946
+ "stream",
947
+ "temperature"
952
948
  ],
953
949
  "frozen": false,
954
- "icon": "braces",
950
+ "icon": "brain-circuit",
951
+ "last_updated": "2025-12-18T20:14:17.831Z",
955
952
  "legacy": false,
956
953
  "lf_version": "1.7.0",
957
954
  "metadata": {
958
- "code_hash": "3cda25c3f7b5",
955
+ "code_hash": "7fe3257f2169",
959
956
  "dependencies": {
960
957
  "dependencies": [
961
958
  {
@@ -965,7 +962,13 @@
965
962
  ],
966
963
  "total_dependencies": 1
967
964
  },
968
- "module": "lfx.components.processing.parser.ParserComponent"
965
+ "keywords": [
966
+ "model",
967
+ "llm",
968
+ "language model",
969
+ "large language model"
970
+ ],
971
+ "module": "lfx.components.models_and_agents.language_model.LanguageModelComponent"
969
972
  },
970
973
  "minimized": false,
971
974
  "output_types": [],
@@ -973,120 +976,134 @@
973
976
  {
974
977
  "allows_loop": false,
975
978
  "cache": true,
976
- "display_name": "Parsed Text",
979
+ "display_name": "Model Response",
977
980
  "group_outputs": false,
978
- "method": "parse_combined_text",
979
- "name": "parsed_text",
981
+ "hidden": null,
982
+ "loop_types": null,
983
+ "method": "text_response",
984
+ "name": "text_output",
985
+ "options": null,
986
+ "required_inputs": null,
980
987
  "selected": "Message",
981
988
  "tool_mode": true,
982
989
  "types": [
983
990
  "Message"
984
991
  ],
985
992
  "value": "__UNDEFINED__"
993
+ },
994
+ {
995
+ "allows_loop": false,
996
+ "cache": true,
997
+ "display_name": "Language Model",
998
+ "group_outputs": false,
999
+ "hidden": null,
1000
+ "loop_types": null,
1001
+ "method": "build_model",
1002
+ "name": "model_output",
1003
+ "options": null,
1004
+ "required_inputs": null,
1005
+ "selected": "LanguageModel",
1006
+ "tool_mode": true,
1007
+ "types": [
1008
+ "LanguageModel"
1009
+ ],
1010
+ "value": "__UNDEFINED__"
986
1011
  }
987
1012
  ],
988
1013
  "pinned": false,
1014
+ "priority": 0,
989
1015
  "template": {
1016
+ "_frontend_node_flow_id": {
1017
+ "value": "70f6d78d-41ad-42a3-854d-405e161ee563"
1018
+ },
1019
+ "_frontend_node_folder_id": {
1020
+ "value": "afaca9ee-97e3-4211-8569-722a4058ea5e"
1021
+ },
990
1022
  "_type": "Component",
991
- "code": {
1023
+ "api_key": {
1024
+ "_input_type": "SecretStrInput",
992
1025
  "advanced": true,
993
- "dynamic": true,
994
- "fileTypes": [],
995
- "file_path": "",
996
- "info": "",
997
- "list": false,
998
- "load_from_db": false,
999
- "multiline": true,
1000
- "name": "code",
1001
- "password": false,
1002
- "placeholder": "",
1003
- "required": true,
1004
- "show": true,
1005
- "title_case": false,
1006
- "type": "code",
1007
- "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"
1008
- },
1009
- "input_data": {
1010
- "_input_type": "HandleInput",
1011
- "advanced": false,
1012
- "display_name": "Data or DataFrame",
1026
+ "display_name": "API Key",
1013
1027
  "dynamic": false,
1014
- "info": "Accepts either a DataFrame or a Data object.",
1015
- "input_types": [
1016
- "DataFrame",
1017
- "Data"
1018
- ],
1019
- "list": false,
1020
- "list_add_label": "Add More",
1021
- "name": "input_data",
1028
+ "info": "Model Provider API key",
1029
+ "input_types": [],
1030
+ "load_from_db": false,
1031
+ "name": "api_key",
1032
+ "override_skip": false,
1033
+ "password": true,
1022
1034
  "placeholder": "",
1023
- "required": true,
1035
+ "real_time_refresh": true,
1036
+ "required": false,
1024
1037
  "show": true,
1025
1038
  "title_case": false,
1026
- "trace_as_metadata": true,
1027
- "type": "other",
1039
+ "track_in_telemetry": false,
1040
+ "type": "str",
1028
1041
  "value": ""
1029
1042
  },
1030
- "mode": {
1031
- "_input_type": "TabInput",
1043
+ "base_url_ibm_watsonx": {
1044
+ "_input_type": "DropdownInput",
1032
1045
  "advanced": false,
1033
- "display_name": "Mode",
1046
+ "combobox": false,
1047
+ "dialog_inputs": {},
1048
+ "display_name": "watsonx API Endpoint",
1034
1049
  "dynamic": false,
1035
- "info": "Convert into raw string instead of using a template.",
1036
- "load_from_db": false,
1037
- "name": "mode",
1050
+ "external_options": {},
1051
+ "info": "The base URL of the API (IBM watsonx.ai only)",
1052
+ "name": "base_url_ibm_watsonx",
1038
1053
  "options": [
1039
- "Parser",
1040
- "Stringify"
1054
+ "https://us-south.ml.cloud.ibm.com",
1055
+ "https://eu-de.ml.cloud.ibm.com",
1056
+ "https://eu-gb.ml.cloud.ibm.com",
1057
+ "https://au-syd.ml.cloud.ibm.com",
1058
+ "https://jp-tok.ml.cloud.ibm.com",
1059
+ "https://ca-tor.ml.cloud.ibm.com"
1041
1060
  ],
1061
+ "options_metadata": [],
1062
+ "override_skip": false,
1042
1063
  "placeholder": "",
1043
1064
  "real_time_refresh": true,
1044
1065
  "required": false,
1045
- "show": true,
1066
+ "show": false,
1046
1067
  "title_case": false,
1068
+ "toggle": false,
1047
1069
  "tool_mode": false,
1048
1070
  "trace_as_metadata": true,
1049
- "type": "tab",
1050
- "value": "Stringify"
1071
+ "track_in_telemetry": true,
1072
+ "type": "str",
1073
+ "value": "https://us-south.ml.cloud.ibm.com"
1051
1074
  },
1052
- "pattern": {
1053
- "_input_type": "MultilineInput",
1054
- "advanced": false,
1055
- "copy_field": false,
1056
- "display_name": "Template",
1075
+ "code": {
1076
+ "advanced": true,
1057
1077
  "dynamic": true,
1058
- "info": "Use variables within curly brackets to extract column values for DataFrames or key values for Data.For example: `Name: {Name}, Age: {Age}, Country: {Country}`",
1059
- "input_types": [
1060
- "Message"
1061
- ],
1078
+ "fileTypes": [],
1079
+ "file_path": "",
1080
+ "info": "",
1062
1081
  "list": false,
1063
- "list_add_label": "Add More",
1064
1082
  "load_from_db": false,
1065
1083
  "multiline": true,
1066
- "name": "pattern",
1084
+ "name": "code",
1085
+ "password": false,
1067
1086
  "placeholder": "",
1068
1087
  "required": true,
1069
1088
  "show": true,
1070
1089
  "title_case": false,
1071
- "tool_mode": false,
1072
- "trace_as_input": true,
1073
- "trace_as_metadata": true,
1074
- "type": "str",
1075
- "value": "Text: {dt}"
1090
+ "type": "code",
1091
+ "value": "from lfx.base.models.model import LCModelComponent\nfrom lfx.base.models.unified_models import (\n get_language_model_options,\n get_llm,\n update_model_options_in_build_config,\n)\nfrom lfx.base.models.watsonx_constants import IBM_WATSONX_URLS\nfrom lfx.field_typing import LanguageModel\nfrom lfx.field_typing.range_spec import RangeSpec\nfrom lfx.inputs.inputs import BoolInput, DropdownInput, StrInput\nfrom lfx.io import MessageInput, ModelInput, MultilineInput, SecretStrInput, SliderInput\n\nDEFAULT_OLLAMA_URL = \"http://localhost:11434\"\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider.\"\n documentation: str = \"https://docs.langflow.org/components-models\"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n ModelInput(\n name=\"model\",\n display_name=\"Language Model\",\n info=\"Select your model provider\",\n real_time_refresh=True,\n required=True,\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"base_url_ibm_watsonx\",\n display_name=\"watsonx API Endpoint\",\n info=\"The base URL of the API (IBM watsonx.ai only)\",\n options=IBM_WATSONX_URLS,\n value=IBM_WATSONX_URLS[0],\n show=False,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"project_id\",\n display_name=\"watsonx Project ID\",\n info=\"The project ID associated with the foundation model (IBM watsonx.ai only)\",\n show=False,\n required=False,\n ),\n MessageInput(\n name=\"ollama_base_url\",\n display_name=\"Ollama API URL\",\n info=f\"Endpoint of the Ollama API (Ollama only). Defaults to {DEFAULT_OLLAMA_URL}\",\n value=DEFAULT_OLLAMA_URL,\n show=False,\n real_time_refresh=True,\n load_from_db=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=False,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n return get_llm(\n model=self.model,\n user_id=self.user_id,\n api_key=self.api_key,\n temperature=self.temperature,\n stream=self.stream,\n )\n\n def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):\n \"\"\"Dynamically update build config with user-filtered model options.\"\"\"\n return update_model_options_in_build_config(\n component=self,\n build_config=build_config,\n cache_key_prefix=\"language_model_options\",\n get_options_func=get_language_model_options,\n field_name=field_name,\n field_value=field_value,\n )\n"
1076
1092
  },
1077
- "sep": {
1078
- "_input_type": "MessageTextInput",
1079
- "advanced": true,
1080
- "display_name": "Separator",
1093
+ "input_value": {
1094
+ "_input_type": "MessageInput",
1095
+ "advanced": false,
1096
+ "display_name": "Input",
1081
1097
  "dynamic": false,
1082
- "info": "String used to separate rows/items.",
1098
+ "info": "The input text to send to the model",
1083
1099
  "input_types": [
1084
1100
  "Message"
1085
1101
  ],
1086
1102
  "list": false,
1087
1103
  "list_add_label": "Add More",
1088
1104
  "load_from_db": false,
1089
- "name": "sep",
1105
+ "name": "input_value",
1106
+ "override_skip": false,
1090
1107
  "placeholder": "",
1091
1108
  "required": false,
1092
1109
  "show": true,
@@ -1094,351 +1111,11 @@
1094
1111
  "tool_mode": false,
1095
1112
  "trace_as_input": true,
1096
1113
  "trace_as_metadata": true,
1097
- "type": "str",
1098
- "value": "\n"
1099
- }
1100
- },
1101
- "tool_mode": false
1102
- },
1103
- "showNode": true,
1104
- "type": "ParserComponent"
1105
- },
1106
- "dragging": false,
1107
- "id": "ParserComponent-E1d8t",
1108
- "measured": {
1109
- "height": 329,
1110
- "width": 320
1111
- },
1112
- "position": {
1113
- "x": 971.3987248215344,
1114
- "y": -186.6658506576822
1115
- },
1116
- "selected": false,
1117
- "type": "genericNode"
1118
- },
1119
- {
1120
- "data": {
1121
- "id": "LoopComponent-qcJgH",
1122
- "node": {
1123
- "base_classes": [
1124
- "Data",
1125
- "DataFrame"
1126
- ],
1127
- "beta": false,
1128
- "conditional_paths": [],
1129
- "custom_fields": {},
1130
- "description": "Iterates over a list of Data or Message objects, outputting one item at a time and aggregating results from loop inputs. Message objects are automatically converted to Data objects for consistent processing.",
1131
- "display_name": "Loop",
1132
- "documentation": "",
1133
- "edited": false,
1134
- "field_order": [
1135
- "data"
1136
- ],
1137
- "frozen": false,
1138
- "icon": "infinity",
1139
- "legacy": false,
1140
- "lf_version": "1.7.0",
1141
- "metadata": {
1142
- "code_hash": "e179036a232d",
1143
- "dependencies": {
1144
- "dependencies": [
1145
- {
1146
- "name": "lfx",
1147
- "version": null
1148
- }
1149
- ],
1150
- "total_dependencies": 1
1151
- },
1152
- "module": "lfx.components.flow_controls.loop.LoopComponent"
1153
- },
1154
- "minimized": false,
1155
- "output_types": [],
1156
- "outputs": [
1157
- {
1158
- "allows_loop": true,
1159
- "cache": true,
1160
- "display_name": "Item",
1161
- "group_outputs": true,
1162
- "loop_types": [
1163
- "Message"
1164
- ],
1165
- "method": "item_output",
1166
- "name": "item",
1167
- "selected": "Data",
1168
- "tool_mode": true,
1169
- "types": [
1170
- "Data"
1171
- ],
1172
- "value": "__UNDEFINED__"
1173
- },
1174
- {
1175
- "allows_loop": false,
1176
- "cache": true,
1177
- "display_name": "Done",
1178
- "group_outputs": true,
1179
- "method": "done_output",
1180
- "name": "done",
1181
- "selected": "DataFrame",
1182
- "tool_mode": true,
1183
- "types": [
1184
- "DataFrame"
1185
- ],
1186
- "value": "__UNDEFINED__"
1187
- }
1188
- ],
1189
- "pinned": false,
1190
- "template": {
1191
- "_type": "Component",
1192
- "code": {
1193
- "advanced": true,
1194
- "dynamic": true,
1195
- "fileTypes": [],
1196
- "file_path": "",
1197
- "info": "",
1198
- "list": false,
1199
- "load_from_db": false,
1200
- "multiline": true,
1201
- "name": "code",
1202
- "password": false,
1203
- "placeholder": "",
1204
- "required": true,
1205
- "show": true,
1206
- "title_case": false,
1207
- "type": "code",
1208
- "value": "from lfx.components.processing.converter import convert_to_data\nfrom lfx.custom.custom_component.component import Component\nfrom lfx.inputs.inputs import HandleInput\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 LoopComponent(Component):\n display_name = \"Loop\"\n description = (\n \"Iterates over a list of Data or Message objects, outputting one item at a time and \"\n \"aggregating results from loop inputs. Message objects are automatically converted to \"\n \"Data objects for consistent processing.\"\n )\n documentation: str = \"https://docs.langflow.org/loop\"\n icon = \"infinity\"\n\n inputs = [\n HandleInput(\n name=\"data\",\n display_name=\"Inputs\",\n info=\"The initial DataFrame to iterate over.\",\n input_types=[\"DataFrame\"],\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Item\",\n name=\"item\",\n method=\"item_output\",\n allows_loop=True,\n loop_types=[\"Message\"],\n group_outputs=True,\n ),\n Output(display_name=\"Done\", name=\"done\", method=\"done_output\", group_outputs=True),\n ]\n\n def initialize_data(self) -> None:\n \"\"\"Initialize the data list, context index, and aggregated list.\"\"\"\n if self.ctx.get(f\"{self._id}_initialized\", False):\n return\n\n # Ensure data is a list of Data objects\n data_list = self._validate_data(self.data)\n\n # Store the initial data and context variables\n self.update_ctx(\n {\n f\"{self._id}_data\": data_list,\n f\"{self._id}_index\": 0,\n f\"{self._id}_aggregated\": [],\n f\"{self._id}_initialized\": True,\n }\n )\n\n def _convert_message_to_data(self, message: Message) -> Data:\n \"\"\"Convert a Message object to a Data object using Type Convert logic.\"\"\"\n return convert_to_data(message, auto_parse=False)\n\n def _validate_data(self, data):\n \"\"\"Validate and return a list of Data objects. Message objects are auto-converted to Data.\"\"\"\n if isinstance(data, DataFrame):\n return data.to_data_list()\n if isinstance(data, Data):\n return [data]\n if isinstance(data, Message):\n # Auto-convert Message to Data\n converted_data = self._convert_message_to_data(data)\n return [converted_data]\n if isinstance(data, list) and all(isinstance(item, (Data, Message)) for item in data):\n # Convert any Message objects in the list to Data objects\n converted_list = []\n for item in data:\n if isinstance(item, Message):\n converted_list.append(self._convert_message_to_data(item))\n else:\n converted_list.append(item)\n return converted_list\n msg = \"The 'data' input must be a DataFrame, a list of Data/Message objects, or a single Data/Message object.\"\n raise TypeError(msg)\n\n def evaluate_stop_loop(self) -> bool:\n \"\"\"Evaluate whether to stop item or done output.\"\"\"\n current_index = self.ctx.get(f\"{self._id}_index\", 0)\n data_length = len(self.ctx.get(f\"{self._id}_data\", []))\n return current_index > data_length\n\n def item_output(self) -> Data:\n \"\"\"Output the next item in the list or stop if done.\"\"\"\n self.initialize_data()\n current_item = Data(text=\"\")\n\n if self.evaluate_stop_loop():\n self.stop(\"item\")\n else:\n # Get data list and current index\n data_list, current_index = self.loop_variables()\n if current_index < len(data_list):\n # Output current item and increment index\n try:\n current_item = data_list[current_index]\n except IndexError:\n current_item = Data(text=\"\")\n self.aggregated_output()\n self.update_ctx({f\"{self._id}_index\": current_index + 1})\n\n # Now we need to update the dependencies for the next run\n self.update_dependency()\n return current_item\n\n def update_dependency(self):\n item_dependency_id = self.get_incoming_edge_by_target_param(\"item\")\n if item_dependency_id not in self.graph.run_manager.run_predecessors[self._id]:\n self.graph.run_manager.run_predecessors[self._id].append(item_dependency_id)\n # CRITICAL: Also update run_map so remove_from_predecessors() works correctly\n # run_map[predecessor] = list of vertices that depend on predecessor\n if self._id not in self.graph.run_manager.run_map[item_dependency_id]:\n self.graph.run_manager.run_map[item_dependency_id].append(self._id)\n\n def done_output(self) -> DataFrame:\n \"\"\"Trigger the done output when iteration is complete.\"\"\"\n self.initialize_data()\n\n if self.evaluate_stop_loop():\n self.stop(\"item\")\n self.start(\"done\")\n\n aggregated = self.ctx.get(f\"{self._id}_aggregated\", [])\n\n return DataFrame(aggregated)\n self.stop(\"done\")\n return DataFrame([])\n\n def loop_variables(self):\n \"\"\"Retrieve loop variables from context.\"\"\"\n return (\n self.ctx.get(f\"{self._id}_data\", []),\n self.ctx.get(f\"{self._id}_index\", 0),\n )\n\n def aggregated_output(self) -> list[Data]:\n \"\"\"Return the aggregated list once all items are processed.\n\n Returns Data or Message objects depending on loop input types.\n \"\"\"\n self.initialize_data()\n\n # Get data list and aggregated list\n data_list = self.ctx.get(f\"{self._id}_data\", [])\n aggregated = self.ctx.get(f\"{self._id}_aggregated\", [])\n loop_input = self.item\n\n # Append the current loop input to aggregated if it's not already included\n if loop_input is not None and not isinstance(loop_input, str) and len(aggregated) <= len(data_list):\n # If the loop input is a Message, convert it to Data for consistency\n if isinstance(loop_input, Message):\n loop_input = self._convert_message_to_data(loop_input)\n aggregated.append(loop_input)\n self.update_ctx({f\"{self._id}_aggregated\": aggregated})\n return aggregated\n"
1209
- },
1210
- "data": {
1211
- "_input_type": "HandleInput",
1212
- "advanced": false,
1213
- "display_name": "Inputs",
1214
- "dynamic": false,
1215
- "info": "The initial DataFrame to iterate over.",
1216
- "input_types": [
1217
- "DataFrame"
1218
- ],
1219
- "list": false,
1220
- "list_add_label": "Add More",
1221
- "name": "data",
1222
- "placeholder": "",
1223
- "required": false,
1224
- "show": true,
1225
- "title_case": false,
1226
- "trace_as_metadata": true,
1227
- "type": "other",
1228
- "value": ""
1229
- }
1230
- },
1231
- "tool_mode": false
1232
- },
1233
- "showNode": true,
1234
- "type": "LoopComponent"
1235
- },
1236
- "dragging": false,
1237
- "id": "LoopComponent-qcJgH",
1238
- "measured": {
1239
- "height": 274,
1240
- "width": 320
1241
- },
1242
- "position": {
1243
- "x": 541.1188345961908,
1244
- "y": 181.38181401206583
1245
- },
1246
- "selected": false,
1247
- "type": "genericNode"
1248
- },
1249
- {
1250
- "data": {
1251
- "id": "LanguageModelComponent-khJQA",
1252
- "node": {
1253
- "base_classes": [
1254
- "LanguageModel",
1255
- "Message"
1256
- ],
1257
- "beta": false,
1258
- "conditional_paths": [],
1259
- "custom_fields": {},
1260
- "description": "Runs a language model given a specified provider.",
1261
- "display_name": "Language Model",
1262
- "documentation": "https://docs.langflow.org/components-models",
1263
- "edited": false,
1264
- "field_order": [
1265
- "model",
1266
- "api_key",
1267
- "base_url_ibm_watsonx",
1268
- "project_id",
1269
- "ollama_base_url",
1270
- "input_value",
1271
- "system_message",
1272
- "stream",
1273
- "temperature"
1274
- ],
1275
- "frozen": false,
1276
- "icon": "brain-circuit",
1277
- "last_updated": "2025-12-15T21:00:37.811Z",
1278
- "legacy": false,
1279
- "metadata": {
1280
- "code_hash": "7fe3257f2169",
1281
- "dependencies": {
1282
- "dependencies": [
1283
- {
1284
- "name": "lfx",
1285
- "version": null
1286
- }
1287
- ],
1288
- "total_dependencies": 1
1289
- },
1290
- "keywords": [
1291
- "model",
1292
- "llm",
1293
- "language model",
1294
- "large language model"
1295
- ],
1296
- "module": "lfx.components.models_and_agents.language_model.LanguageModelComponent"
1297
- },
1298
- "minimized": false,
1299
- "output_types": [],
1300
- "outputs": [
1301
- {
1302
- "allows_loop": false,
1303
- "cache": true,
1304
- "display_name": "Model Response",
1305
- "group_outputs": false,
1306
- "loop_types": null,
1307
- "method": "text_response",
1308
- "name": "text_output",
1309
- "options": null,
1310
- "required_inputs": null,
1311
- "selected": "Message",
1312
- "tool_mode": true,
1313
- "types": [
1314
- "Message"
1315
- ],
1316
- "value": "__UNDEFINED__"
1317
- },
1318
- {
1319
- "allows_loop": false,
1320
- "cache": true,
1321
- "display_name": "Language Model",
1322
- "group_outputs": false,
1323
- "loop_types": null,
1324
- "method": "build_model",
1325
- "name": "model_output",
1326
- "options": null,
1327
- "required_inputs": null,
1328
- "selected": "LanguageModel",
1329
- "tool_mode": true,
1330
- "types": [
1331
- "LanguageModel"
1332
- ],
1333
- "value": "__UNDEFINED__"
1334
- }
1335
- ],
1336
- "pinned": false,
1337
- "priority": 0,
1338
- "template": {
1339
- "_frontend_node_flow_id": {
1340
- "value": "bf9b5a44-29d7-4301-bcc2-1601cf905efe"
1341
- },
1342
- "_frontend_node_folder_id": {
1343
- "value": "afaca9ee-97e3-4211-8569-722a4058ea5e"
1344
- },
1345
- "_type": "Component",
1346
- "api_key": {
1347
- "_input_type": "SecretStrInput",
1348
- "advanced": true,
1349
- "display_name": "API Key",
1350
- "dynamic": false,
1351
- "info": "Model Provider API key",
1352
- "input_types": [],
1353
- "load_from_db": false,
1354
- "name": "api_key",
1355
- "override_skip": false,
1356
- "password": true,
1357
- "placeholder": "",
1358
- "real_time_refresh": true,
1359
- "required": false,
1360
- "show": true,
1361
- "title_case": false,
1362
- "track_in_telemetry": false,
1363
- "type": "str",
1364
- "value": ""
1365
- },
1366
- "base_url_ibm_watsonx": {
1367
- "_input_type": "DropdownInput",
1368
- "advanced": false,
1369
- "combobox": false,
1370
- "dialog_inputs": {},
1371
- "display_name": "watsonx API Endpoint",
1372
- "dynamic": false,
1373
- "external_options": {},
1374
- "info": "The base URL of the API (IBM watsonx.ai only)",
1375
- "name": "base_url_ibm_watsonx",
1376
- "options": [
1377
- "https://us-south.ml.cloud.ibm.com",
1378
- "https://eu-de.ml.cloud.ibm.com",
1379
- "https://eu-gb.ml.cloud.ibm.com",
1380
- "https://au-syd.ml.cloud.ibm.com",
1381
- "https://jp-tok.ml.cloud.ibm.com",
1382
- "https://ca-tor.ml.cloud.ibm.com"
1383
- ],
1384
- "options_metadata": [],
1385
- "override_skip": false,
1386
- "placeholder": "",
1387
- "real_time_refresh": true,
1388
- "required": false,
1389
- "show": false,
1390
- "title_case": false,
1391
- "toggle": false,
1392
- "tool_mode": false,
1393
- "trace_as_metadata": true,
1394
- "track_in_telemetry": true,
1395
- "type": "str",
1396
- "value": "https://us-south.ml.cloud.ibm.com"
1397
- },
1398
- "code": {
1399
- "advanced": true,
1400
- "dynamic": true,
1401
- "fileTypes": [],
1402
- "file_path": "",
1403
- "info": "",
1404
- "list": false,
1405
- "load_from_db": false,
1406
- "multiline": true,
1407
- "name": "code",
1408
- "password": false,
1409
- "placeholder": "",
1410
- "required": true,
1411
- "show": true,
1412
- "title_case": false,
1413
- "type": "code",
1414
- "value": "from lfx.base.models.model import LCModelComponent\nfrom lfx.base.models.unified_models import (\n get_language_model_options,\n get_llm,\n update_model_options_in_build_config,\n)\nfrom lfx.base.models.watsonx_constants import IBM_WATSONX_URLS\nfrom lfx.field_typing import LanguageModel\nfrom lfx.field_typing.range_spec import RangeSpec\nfrom lfx.inputs.inputs import BoolInput, DropdownInput, StrInput\nfrom lfx.io import MessageInput, ModelInput, MultilineInput, SecretStrInput, SliderInput\n\nDEFAULT_OLLAMA_URL = \"http://localhost:11434\"\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider.\"\n documentation: str = \"https://docs.langflow.org/components-models\"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n ModelInput(\n name=\"model\",\n display_name=\"Language Model\",\n info=\"Select your model provider\",\n real_time_refresh=True,\n required=True,\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"base_url_ibm_watsonx\",\n display_name=\"watsonx API Endpoint\",\n info=\"The base URL of the API (IBM watsonx.ai only)\",\n options=IBM_WATSONX_URLS,\n value=IBM_WATSONX_URLS[0],\n show=False,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"project_id\",\n display_name=\"watsonx Project ID\",\n info=\"The project ID associated with the foundation model (IBM watsonx.ai only)\",\n show=False,\n required=False,\n ),\n MessageInput(\n name=\"ollama_base_url\",\n display_name=\"Ollama API URL\",\n info=f\"Endpoint of the Ollama API (Ollama only). Defaults to {DEFAULT_OLLAMA_URL}\",\n value=DEFAULT_OLLAMA_URL,\n show=False,\n real_time_refresh=True,\n load_from_db=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=False,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n return get_llm(\n model=self.model,\n user_id=self.user_id,\n api_key=self.api_key,\n temperature=self.temperature,\n stream=self.stream,\n )\n\n def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):\n \"\"\"Dynamically update build config with user-filtered model options.\"\"\"\n return update_model_options_in_build_config(\n component=self,\n build_config=build_config,\n cache_key_prefix=\"language_model_options\",\n get_options_func=get_language_model_options,\n field_name=field_name,\n field_value=field_value,\n )\n"
1415
- },
1416
- "input_value": {
1417
- "_input_type": "MessageInput",
1418
- "advanced": false,
1419
- "display_name": "Input",
1420
- "dynamic": false,
1421
- "info": "The input text to send to the model",
1422
- "input_types": [
1423
- "Message"
1424
- ],
1425
- "list": false,
1426
- "list_add_label": "Add More",
1427
- "load_from_db": false,
1428
- "name": "input_value",
1429
- "override_skip": false,
1430
- "placeholder": "",
1431
- "required": false,
1432
- "show": true,
1433
- "title_case": false,
1434
- "tool_mode": false,
1435
- "trace_as_input": true,
1436
- "trace_as_metadata": true,
1437
- "track_in_telemetry": false,
1114
+ "track_in_telemetry": false,
1438
1115
  "type": "str",
1439
1116
  "value": ""
1440
1117
  },
1441
- "is_refresh": false,
1118
+ "is_refresh": true,
1442
1119
  "model": {
1443
1120
  "_input_type": "ModelInput",
1444
1121
  "advanced": false,
@@ -1541,25 +1218,41 @@
1541
1218
  "provider": "OpenAI"
1542
1219
  },
1543
1220
  {
1544
- "category": "Google Generative AI",
1545
- "icon": "GoogleGenerativeAI",
1221
+ "category": "Ollama",
1222
+ "icon": "Ollama",
1546
1223
  "metadata": {
1547
- "is_disabled_provider": true,
1548
- "variable_name": "GOOGLE_API_KEY"
1224
+ "api_key_param": "base_url",
1225
+ "base_url_param": "base_url",
1226
+ "context_length": 128000,
1227
+ "model_class": "ChatOllama",
1228
+ "model_name_param": "model"
1549
1229
  },
1550
- "name": "__enable_provider_Google Generative AI__",
1551
- "provider": "Google Generative AI"
1230
+ "name": "llama3.3",
1231
+ "provider": "Ollama"
1552
1232
  },
1553
1233
  {
1554
1234
  "category": "Ollama",
1555
1235
  "icon": "Ollama",
1556
1236
  "metadata": {
1557
- "is_disabled_provider": true,
1558
- "variable_name": "OLLAMA_BASE_URL"
1237
+ "api_key_param": "base_url",
1238
+ "base_url_param": "base_url",
1239
+ "context_length": 128000,
1240
+ "model_class": "ChatOllama",
1241
+ "model_name_param": "model"
1559
1242
  },
1560
- "name": "__enable_provider_Ollama__",
1243
+ "name": "qwq",
1561
1244
  "provider": "Ollama"
1562
1245
  },
1246
+ {
1247
+ "category": "Google Generative AI",
1248
+ "icon": "GoogleGenerativeAI",
1249
+ "metadata": {
1250
+ "is_disabled_provider": true,
1251
+ "variable_name": "GOOGLE_API_KEY"
1252
+ },
1253
+ "name": "__enable_provider_Google Generative AI__",
1254
+ "provider": "Google Generative AI"
1255
+ },
1563
1256
  {
1564
1257
  "category": "IBM Watsonx",
1565
1258
  "icon": "WatsonxAI",
@@ -1571,106 +1264,440 @@
1571
1264
  "provider": "IBM Watsonx"
1572
1265
  }
1573
1266
  ],
1574
- "override_skip": false,
1575
- "placeholder": "Setup Provider",
1576
- "real_time_refresh": true,
1577
- "refresh_button": true,
1267
+ "override_skip": false,
1268
+ "placeholder": "Setup Provider",
1269
+ "real_time_refresh": true,
1270
+ "refresh_button": true,
1271
+ "required": true,
1272
+ "show": true,
1273
+ "title_case": false,
1274
+ "tool_mode": false,
1275
+ "trace_as_input": true,
1276
+ "track_in_telemetry": false,
1277
+ "type": "model",
1278
+ "value": [
1279
+ {
1280
+ "category": "OpenAI",
1281
+ "icon": "OpenAI",
1282
+ "metadata": {
1283
+ "api_key_param": "api_key",
1284
+ "context_length": 128000,
1285
+ "model_class": "ChatOpenAI",
1286
+ "model_name_param": "model",
1287
+ "reasoning_models": [
1288
+ "gpt-5.1"
1289
+ ]
1290
+ },
1291
+ "name": "gpt-5.1",
1292
+ "provider": "OpenAI"
1293
+ }
1294
+ ]
1295
+ },
1296
+ "ollama_base_url": {
1297
+ "_input_type": "MessageInput",
1298
+ "advanced": false,
1299
+ "display_name": "Ollama API URL",
1300
+ "dynamic": false,
1301
+ "info": "Endpoint of the Ollama API (Ollama only). Defaults to http://localhost:11434",
1302
+ "input_types": [
1303
+ "Message"
1304
+ ],
1305
+ "list": false,
1306
+ "list_add_label": "Add More",
1307
+ "load_from_db": false,
1308
+ "name": "ollama_base_url",
1309
+ "override_skip": false,
1310
+ "placeholder": "",
1311
+ "real_time_refresh": true,
1312
+ "required": false,
1313
+ "show": false,
1314
+ "title_case": false,
1315
+ "tool_mode": false,
1316
+ "trace_as_input": true,
1317
+ "trace_as_metadata": true,
1318
+ "track_in_telemetry": false,
1319
+ "type": "str",
1320
+ "value": ""
1321
+ },
1322
+ "project_id": {
1323
+ "_input_type": "StrInput",
1324
+ "advanced": false,
1325
+ "display_name": "watsonx Project ID",
1326
+ "dynamic": false,
1327
+ "info": "The project ID associated with the foundation model (IBM watsonx.ai only)",
1328
+ "list": false,
1329
+ "list_add_label": "Add More",
1330
+ "load_from_db": false,
1331
+ "name": "project_id",
1332
+ "override_skip": false,
1333
+ "placeholder": "",
1334
+ "required": false,
1335
+ "show": false,
1336
+ "title_case": false,
1337
+ "tool_mode": false,
1338
+ "trace_as_metadata": true,
1339
+ "track_in_telemetry": false,
1340
+ "type": "str",
1341
+ "value": ""
1342
+ },
1343
+ "stream": {
1344
+ "_input_type": "BoolInput",
1345
+ "advanced": true,
1346
+ "display_name": "Stream",
1347
+ "dynamic": false,
1348
+ "info": "Whether to stream the response",
1349
+ "list": false,
1350
+ "list_add_label": "Add More",
1351
+ "name": "stream",
1352
+ "override_skip": false,
1353
+ "placeholder": "",
1354
+ "required": false,
1355
+ "show": true,
1356
+ "title_case": false,
1357
+ "tool_mode": false,
1358
+ "trace_as_metadata": true,
1359
+ "track_in_telemetry": true,
1360
+ "type": "bool",
1361
+ "value": false
1362
+ },
1363
+ "system_message": {
1364
+ "_input_type": "MultilineInput",
1365
+ "advanced": false,
1366
+ "ai_enabled": false,
1367
+ "copy_field": false,
1368
+ "display_name": "System Message",
1369
+ "dynamic": false,
1370
+ "info": "A system message that helps set the behavior of the assistant",
1371
+ "input_types": [
1372
+ "Message"
1373
+ ],
1374
+ "list": false,
1375
+ "list_add_label": "Add More",
1376
+ "load_from_db": false,
1377
+ "multiline": true,
1378
+ "name": "system_message",
1379
+ "override_skip": false,
1380
+ "placeholder": "",
1381
+ "required": false,
1382
+ "show": true,
1383
+ "title_case": false,
1384
+ "tool_mode": false,
1385
+ "trace_as_input": true,
1386
+ "trace_as_metadata": true,
1387
+ "track_in_telemetry": false,
1388
+ "type": "str",
1389
+ "value": ""
1390
+ },
1391
+ "temperature": {
1392
+ "_input_type": "SliderInput",
1393
+ "advanced": true,
1394
+ "display_name": "Temperature",
1395
+ "dynamic": false,
1396
+ "info": "Controls randomness in responses",
1397
+ "max_label": "",
1398
+ "max_label_icon": "",
1399
+ "min_label": "",
1400
+ "min_label_icon": "",
1401
+ "name": "temperature",
1402
+ "override_skip": false,
1403
+ "placeholder": "",
1404
+ "range_spec": {
1405
+ "max": 1,
1406
+ "min": 0,
1407
+ "step": 0.01,
1408
+ "step_type": "float"
1409
+ },
1410
+ "required": false,
1411
+ "show": true,
1412
+ "slider_buttons": false,
1413
+ "slider_buttons_options": [],
1414
+ "slider_input": false,
1415
+ "title_case": false,
1416
+ "tool_mode": false,
1417
+ "track_in_telemetry": false,
1418
+ "type": "slider",
1419
+ "value": 0.1
1420
+ }
1421
+ },
1422
+ "tool_mode": false
1423
+ },
1424
+ "selected_output": "text_output",
1425
+ "showNode": true,
1426
+ "type": "LanguageModelComponent"
1427
+ },
1428
+ "dragging": false,
1429
+ "id": "LanguageModelComponent-XKvly",
1430
+ "measured": {
1431
+ "height": 369,
1432
+ "width": 320
1433
+ },
1434
+ "position": {
1435
+ "x": 1630.638479427766,
1436
+ "y": 116.0160835115366
1437
+ },
1438
+ "selected": false,
1439
+ "type": "genericNode"
1440
+ },
1441
+ {
1442
+ "data": {
1443
+ "id": "LoopComponent-GtPZT",
1444
+ "node": {
1445
+ "base_classes": [
1446
+ "Data",
1447
+ "DataFrame"
1448
+ ],
1449
+ "beta": false,
1450
+ "conditional_paths": [],
1451
+ "custom_fields": {},
1452
+ "description": "Iterates over a list of Data or Message objects, outputting one item at a time and aggregating results from loop inputs. Message objects are automatically converted to Data objects for consistent processing.",
1453
+ "display_name": "Loop",
1454
+ "documentation": "https://docs.langflow.org/loop",
1455
+ "edited": false,
1456
+ "field_order": [
1457
+ "data"
1458
+ ],
1459
+ "frozen": false,
1460
+ "icon": "infinity",
1461
+ "legacy": false,
1462
+ "metadata": {
1463
+ "code_hash": "e179036a232d",
1464
+ "dependencies": {
1465
+ "dependencies": [
1466
+ {
1467
+ "name": "lfx",
1468
+ "version": null
1469
+ }
1470
+ ],
1471
+ "total_dependencies": 1
1472
+ },
1473
+ "module": "lfx.components.flow_controls.loop.LoopComponent"
1474
+ },
1475
+ "minimized": false,
1476
+ "output_types": [],
1477
+ "outputs": [
1478
+ {
1479
+ "allows_loop": true,
1480
+ "cache": true,
1481
+ "display_name": "Item",
1482
+ "group_outputs": true,
1483
+ "loop_types": [
1484
+ "Message"
1485
+ ],
1486
+ "method": "item_output",
1487
+ "name": "item",
1488
+ "selected": "Data",
1489
+ "tool_mode": true,
1490
+ "types": [
1491
+ "Data"
1492
+ ],
1493
+ "value": "__UNDEFINED__"
1494
+ },
1495
+ {
1496
+ "allows_loop": false,
1497
+ "cache": true,
1498
+ "display_name": "Done",
1499
+ "group_outputs": true,
1500
+ "method": "done_output",
1501
+ "name": "done",
1502
+ "selected": "DataFrame",
1503
+ "tool_mode": true,
1504
+ "types": [
1505
+ "DataFrame"
1506
+ ],
1507
+ "value": "__UNDEFINED__"
1508
+ }
1509
+ ],
1510
+ "pinned": false,
1511
+ "template": {
1512
+ "_type": "Component",
1513
+ "code": {
1514
+ "advanced": true,
1515
+ "dynamic": true,
1516
+ "fileTypes": [],
1517
+ "file_path": "",
1518
+ "info": "",
1519
+ "list": false,
1520
+ "load_from_db": false,
1521
+ "multiline": true,
1522
+ "name": "code",
1523
+ "password": false,
1524
+ "placeholder": "",
1578
1525
  "required": true,
1579
1526
  "show": true,
1580
1527
  "title_case": false,
1581
- "tool_mode": false,
1582
- "trace_as_input": true,
1583
- "track_in_telemetry": false,
1584
- "type": "model",
1585
- "value": [
1586
- {
1587
- "icon": "OpenAI",
1588
- "metadata": {
1589
- "api_key_param": "api_key",
1590
- "context_length": 128000,
1591
- "model_class": "ChatOpenAI",
1592
- "model_name_param": "model"
1593
- },
1594
- "name": "gpt-4o-mini",
1595
- "provider": "OpenAI"
1596
- }
1597
- ]
1528
+ "type": "code",
1529
+ "value": "from lfx.components.processing.converter import convert_to_data\nfrom lfx.custom.custom_component.component import Component\nfrom lfx.inputs.inputs import HandleInput\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 LoopComponent(Component):\n display_name = \"Loop\"\n description = (\n \"Iterates over a list of Data or Message objects, outputting one item at a time and \"\n \"aggregating results from loop inputs. Message objects are automatically converted to \"\n \"Data objects for consistent processing.\"\n )\n documentation: str = \"https://docs.langflow.org/loop\"\n icon = \"infinity\"\n\n inputs = [\n HandleInput(\n name=\"data\",\n display_name=\"Inputs\",\n info=\"The initial DataFrame to iterate over.\",\n input_types=[\"DataFrame\"],\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Item\",\n name=\"item\",\n method=\"item_output\",\n allows_loop=True,\n loop_types=[\"Message\"],\n group_outputs=True,\n ),\n Output(display_name=\"Done\", name=\"done\", method=\"done_output\", group_outputs=True),\n ]\n\n def initialize_data(self) -> None:\n \"\"\"Initialize the data list, context index, and aggregated list.\"\"\"\n if self.ctx.get(f\"{self._id}_initialized\", False):\n return\n\n # Ensure data is a list of Data objects\n data_list = self._validate_data(self.data)\n\n # Store the initial data and context variables\n self.update_ctx(\n {\n f\"{self._id}_data\": data_list,\n f\"{self._id}_index\": 0,\n f\"{self._id}_aggregated\": [],\n f\"{self._id}_initialized\": True,\n }\n )\n\n def _convert_message_to_data(self, message: Message) -> Data:\n \"\"\"Convert a Message object to a Data object using Type Convert logic.\"\"\"\n return convert_to_data(message, auto_parse=False)\n\n def _validate_data(self, data):\n \"\"\"Validate and return a list of Data objects. Message objects are auto-converted to Data.\"\"\"\n if isinstance(data, DataFrame):\n return data.to_data_list()\n if isinstance(data, Data):\n return [data]\n if isinstance(data, Message):\n # Auto-convert Message to Data\n converted_data = self._convert_message_to_data(data)\n return [converted_data]\n if isinstance(data, list) and all(isinstance(item, (Data, Message)) for item in data):\n # Convert any Message objects in the list to Data objects\n converted_list = []\n for item in data:\n if isinstance(item, Message):\n converted_list.append(self._convert_message_to_data(item))\n else:\n converted_list.append(item)\n return converted_list\n msg = \"The 'data' input must be a DataFrame, a list of Data/Message objects, or a single Data/Message object.\"\n raise TypeError(msg)\n\n def evaluate_stop_loop(self) -> bool:\n \"\"\"Evaluate whether to stop item or done output.\"\"\"\n current_index = self.ctx.get(f\"{self._id}_index\", 0)\n data_length = len(self.ctx.get(f\"{self._id}_data\", []))\n return current_index > data_length\n\n def item_output(self) -> Data:\n \"\"\"Output the next item in the list or stop if done.\"\"\"\n self.initialize_data()\n current_item = Data(text=\"\")\n\n if self.evaluate_stop_loop():\n self.stop(\"item\")\n else:\n # Get data list and current index\n data_list, current_index = self.loop_variables()\n if current_index < len(data_list):\n # Output current item and increment index\n try:\n current_item = data_list[current_index]\n except IndexError:\n current_item = Data(text=\"\")\n self.aggregated_output()\n self.update_ctx({f\"{self._id}_index\": current_index + 1})\n\n # Now we need to update the dependencies for the next run\n self.update_dependency()\n return current_item\n\n def update_dependency(self):\n item_dependency_id = self.get_incoming_edge_by_target_param(\"item\")\n if item_dependency_id not in self.graph.run_manager.run_predecessors[self._id]:\n self.graph.run_manager.run_predecessors[self._id].append(item_dependency_id)\n # CRITICAL: Also update run_map so remove_from_predecessors() works correctly\n # run_map[predecessor] = list of vertices that depend on predecessor\n if self._id not in self.graph.run_manager.run_map[item_dependency_id]:\n self.graph.run_manager.run_map[item_dependency_id].append(self._id)\n\n def done_output(self) -> DataFrame:\n \"\"\"Trigger the done output when iteration is complete.\"\"\"\n self.initialize_data()\n\n if self.evaluate_stop_loop():\n self.stop(\"item\")\n self.start(\"done\")\n\n aggregated = self.ctx.get(f\"{self._id}_aggregated\", [])\n\n return DataFrame(aggregated)\n self.stop(\"done\")\n return DataFrame([])\n\n def loop_variables(self):\n \"\"\"Retrieve loop variables from context.\"\"\"\n return (\n self.ctx.get(f\"{self._id}_data\", []),\n self.ctx.get(f\"{self._id}_index\", 0),\n )\n\n def aggregated_output(self) -> list[Data]:\n \"\"\"Return the aggregated list once all items are processed.\n\n Returns Data or Message objects depending on loop input types.\n \"\"\"\n self.initialize_data()\n\n # Get data list and aggregated list\n data_list = self.ctx.get(f\"{self._id}_data\", [])\n aggregated = self.ctx.get(f\"{self._id}_aggregated\", [])\n loop_input = self.item\n\n # Append the current loop input to aggregated if it's not already included\n if loop_input is not None and not isinstance(loop_input, str) and len(aggregated) <= len(data_list):\n # If the loop input is a Message, convert it to Data for consistency\n if isinstance(loop_input, Message):\n loop_input = self._convert_message_to_data(loop_input)\n aggregated.append(loop_input)\n self.update_ctx({f\"{self._id}_aggregated\": aggregated})\n return aggregated\n"
1598
1530
  },
1599
- "ollama_base_url": {
1600
- "_input_type": "MessageInput",
1531
+ "data": {
1532
+ "_input_type": "HandleInput",
1601
1533
  "advanced": false,
1602
- "display_name": "Ollama API URL",
1534
+ "display_name": "Inputs",
1603
1535
  "dynamic": false,
1604
- "info": "Endpoint of the Ollama API (Ollama only). Defaults to http://localhost:11434",
1536
+ "info": "The initial DataFrame to iterate over.",
1605
1537
  "input_types": [
1606
- "Message"
1538
+ "DataFrame"
1607
1539
  ],
1608
1540
  "list": false,
1609
1541
  "list_add_label": "Add More",
1610
- "load_from_db": false,
1611
- "name": "ollama_base_url",
1542
+ "name": "data",
1612
1543
  "override_skip": false,
1613
1544
  "placeholder": "",
1614
- "real_time_refresh": true,
1615
1545
  "required": false,
1616
- "show": false,
1546
+ "show": true,
1617
1547
  "title_case": false,
1618
- "tool_mode": false,
1619
- "trace_as_input": true,
1620
1548
  "trace_as_metadata": true,
1621
1549
  "track_in_telemetry": false,
1622
- "type": "str",
1550
+ "type": "other",
1623
1551
  "value": ""
1552
+ }
1553
+ },
1554
+ "tool_mode": false
1555
+ },
1556
+ "showNode": true,
1557
+ "type": "LoopComponent"
1558
+ },
1559
+ "dragging": false,
1560
+ "id": "LoopComponent-GtPZT",
1561
+ "measured": {
1562
+ "height": 274,
1563
+ "width": 320
1564
+ },
1565
+ "position": {
1566
+ "x": 581.346082615804,
1567
+ "y": 105.19270617605812
1568
+ },
1569
+ "selected": false,
1570
+ "type": "genericNode"
1571
+ },
1572
+ {
1573
+ "data": {
1574
+ "id": "ParserComponent-pXAMb",
1575
+ "node": {
1576
+ "base_classes": [
1577
+ "Message"
1578
+ ],
1579
+ "beta": false,
1580
+ "conditional_paths": [],
1581
+ "custom_fields": {},
1582
+ "description": "Extracts text using a template.",
1583
+ "display_name": "Parser",
1584
+ "documentation": "https://docs.langflow.org/parser",
1585
+ "edited": false,
1586
+ "field_order": [
1587
+ "input_data",
1588
+ "mode",
1589
+ "pattern",
1590
+ "sep"
1591
+ ],
1592
+ "frozen": false,
1593
+ "icon": "braces",
1594
+ "legacy": false,
1595
+ "metadata": {
1596
+ "code_hash": "3cda25c3f7b5",
1597
+ "dependencies": {
1598
+ "dependencies": [
1599
+ {
1600
+ "name": "lfx",
1601
+ "version": null
1602
+ }
1603
+ ],
1604
+ "total_dependencies": 1
1624
1605
  },
1625
- "project_id": {
1626
- "_input_type": "StrInput",
1606
+ "module": "lfx.components.processing.parser.ParserComponent"
1607
+ },
1608
+ "minimized": false,
1609
+ "output_types": [],
1610
+ "outputs": [
1611
+ {
1612
+ "allows_loop": false,
1613
+ "cache": true,
1614
+ "display_name": "Parsed Text",
1615
+ "group_outputs": false,
1616
+ "method": "parse_combined_text",
1617
+ "name": "parsed_text",
1618
+ "selected": "Message",
1619
+ "tool_mode": true,
1620
+ "types": [
1621
+ "Message"
1622
+ ],
1623
+ "value": "__UNDEFINED__"
1624
+ }
1625
+ ],
1626
+ "pinned": false,
1627
+ "template": {
1628
+ "_type": "Component",
1629
+ "code": {
1630
+ "advanced": true,
1631
+ "dynamic": true,
1632
+ "fileTypes": [],
1633
+ "file_path": "",
1634
+ "info": "",
1635
+ "list": false,
1636
+ "load_from_db": false,
1637
+ "multiline": true,
1638
+ "name": "code",
1639
+ "password": false,
1640
+ "placeholder": "",
1641
+ "required": true,
1642
+ "show": true,
1643
+ "title_case": false,
1644
+ "type": "code",
1645
+ "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"
1646
+ },
1647
+ "input_data": {
1648
+ "_input_type": "HandleInput",
1627
1649
  "advanced": false,
1628
- "display_name": "watsonx Project ID",
1650
+ "display_name": "Data or DataFrame",
1629
1651
  "dynamic": false,
1630
- "info": "The project ID associated with the foundation model (IBM watsonx.ai only)",
1652
+ "info": "Accepts either a DataFrame or a Data object.",
1653
+ "input_types": [
1654
+ "DataFrame",
1655
+ "Data"
1656
+ ],
1631
1657
  "list": false,
1632
1658
  "list_add_label": "Add More",
1633
- "load_from_db": false,
1634
- "name": "project_id",
1659
+ "name": "input_data",
1635
1660
  "override_skip": false,
1636
1661
  "placeholder": "",
1637
- "required": false,
1638
- "show": false,
1662
+ "required": true,
1663
+ "show": true,
1639
1664
  "title_case": false,
1640
- "tool_mode": false,
1641
1665
  "trace_as_metadata": true,
1642
1666
  "track_in_telemetry": false,
1643
- "type": "str",
1667
+ "type": "other",
1644
1668
  "value": ""
1645
1669
  },
1646
- "stream": {
1647
- "_input_type": "BoolInput",
1648
- "advanced": true,
1649
- "display_name": "Stream",
1670
+ "mode": {
1671
+ "_input_type": "TabInput",
1672
+ "advanced": false,
1673
+ "display_name": "Mode",
1650
1674
  "dynamic": false,
1651
- "info": "Whether to stream the response",
1652
- "list": false,
1653
- "list_add_label": "Add More",
1654
- "name": "stream",
1675
+ "info": "Convert into raw string instead of using a template.",
1676
+ "name": "mode",
1677
+ "options": [
1678
+ "Parser",
1679
+ "Stringify"
1680
+ ],
1655
1681
  "override_skip": false,
1656
1682
  "placeholder": "",
1683
+ "real_time_refresh": true,
1657
1684
  "required": false,
1658
1685
  "show": true,
1659
1686
  "title_case": false,
1660
1687
  "tool_mode": false,
1661
1688
  "trace_as_metadata": true,
1662
1689
  "track_in_telemetry": true,
1663
- "type": "bool",
1664
- "value": false
1690
+ "type": "tab",
1691
+ "value": "Parser"
1665
1692
  },
1666
- "system_message": {
1693
+ "pattern": {
1667
1694
  "_input_type": "MultilineInput",
1668
1695
  "advanced": false,
1669
1696
  "ai_enabled": false,
1670
1697
  "copy_field": false,
1671
- "display_name": "System Message",
1672
- "dynamic": false,
1673
- "info": "A system message that helps set the behavior of the assistant",
1698
+ "display_name": "Template",
1699
+ "dynamic": true,
1700
+ "info": "Use variables within curly brackets to extract column values for DataFrames or key values for Data.For example: `Name: {Name}, Age: {Age}, Country: {Country}`",
1674
1701
  "input_types": [
1675
1702
  "Message"
1676
1703
  ],
@@ -1678,10 +1705,10 @@
1678
1705
  "list_add_label": "Add More",
1679
1706
  "load_from_db": false,
1680
1707
  "multiline": true,
1681
- "name": "system_message",
1708
+ "name": "pattern",
1682
1709
  "override_skip": false,
1683
1710
  "placeholder": "",
1684
- "required": false,
1711
+ "required": true,
1685
1712
  "show": true,
1686
1713
  "title_case": false,
1687
1714
  "tool_mode": false,
@@ -1689,68 +1716,62 @@
1689
1716
  "trace_as_metadata": true,
1690
1717
  "track_in_telemetry": false,
1691
1718
  "type": "str",
1692
- "value": ""
1719
+ "value": "Text: {text}"
1693
1720
  },
1694
- "temperature": {
1695
- "_input_type": "SliderInput",
1721
+ "sep": {
1722
+ "_input_type": "MessageTextInput",
1696
1723
  "advanced": true,
1697
- "display_name": "Temperature",
1724
+ "display_name": "Separator",
1698
1725
  "dynamic": false,
1699
- "info": "Controls randomness in responses",
1700
- "max_label": "",
1701
- "max_label_icon": "",
1702
- "min_label": "",
1703
- "min_label_icon": "",
1704
- "name": "temperature",
1726
+ "info": "String used to separate rows/items.",
1727
+ "input_types": [
1728
+ "Message"
1729
+ ],
1730
+ "list": false,
1731
+ "list_add_label": "Add More",
1732
+ "load_from_db": false,
1733
+ "name": "sep",
1705
1734
  "override_skip": false,
1706
1735
  "placeholder": "",
1707
- "range_spec": {
1708
- "max": 1,
1709
- "min": 0,
1710
- "step": 0.01,
1711
- "step_type": "float"
1712
- },
1713
1736
  "required": false,
1714
1737
  "show": true,
1715
- "slider_buttons": false,
1716
- "slider_buttons_options": [],
1717
- "slider_input": false,
1718
1738
  "title_case": false,
1719
1739
  "tool_mode": false,
1740
+ "trace_as_input": true,
1741
+ "trace_as_metadata": true,
1720
1742
  "track_in_telemetry": false,
1721
- "type": "slider",
1722
- "value": 0.1
1743
+ "type": "str",
1744
+ "value": "\n"
1723
1745
  }
1724
1746
  },
1725
1747
  "tool_mode": false
1726
1748
  },
1727
- "selected_output": "text_output",
1728
1749
  "showNode": true,
1729
- "type": "LanguageModelComponent"
1750
+ "type": "ParserComponent"
1730
1751
  },
1731
1752
  "dragging": false,
1732
- "id": "LanguageModelComponent-khJQA",
1753
+ "id": "ParserComponent-pXAMb",
1733
1754
  "measured": {
1734
- "height": 369,
1755
+ "height": 329,
1735
1756
  "width": 320
1736
1757
  },
1737
1758
  "position": {
1738
- "x": 1432.0732826505218,
1739
- "y": -32.168243534243494
1759
+ "x": 1102.2949192976482,
1760
+ "y": -80.12506181353082
1740
1761
  },
1741
1762
  "selected": false,
1742
1763
  "type": "genericNode"
1743
1764
  }
1744
1765
  ],
1745
1766
  "viewport": {
1746
- "x": 470.0085200553991,
1747
- "y": 327.4433296590934,
1748
- "zoom": 0.44899341935528186
1767
+ "x": 245.66793868161778,
1768
+ "y": 267.9129204471257,
1769
+ "zoom": 0.48565229862392995
1749
1770
  }
1750
1771
  },
1751
1772
  "description": "This template iterates over search results using LoopComponent and translates each result into Portuguese automatically. 🚀",
1752
1773
  "endpoint_name": null,
1753
- "id": "bf9b5a44-29d7-4301-bcc2-1601cf905efe",
1774
+ "id": "70f6d78d-41ad-42a3-854d-405e161ee563",
1754
1775
  "is_component": false,
1755
1776
  "last_tested_version": "1.7.0",
1756
1777
  "name": "Research Translation Loop",