lfx-nightly 0.1.13.dev8__py3-none-any.whl → 0.1.13.dev10__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.
Potentially problematic release.
This version of lfx-nightly might be problematic. Click here for more details.
- lfx/_assets/component_index.json +1 -1
- lfx/base/agents/agent.py +106 -42
- lfx/base/agents/events.py +102 -35
- lfx/base/models/model_input_constants.py +74 -7
- lfx/base/models/ollama_constants.py +3 -0
- lfx/components/agents/agent.py +37 -2
- lfx/components/ibm/watsonx.py +25 -21
- lfx/components/ollama/ollama.py +221 -14
- lfx/schema/schema.py +5 -0
- {lfx_nightly-0.1.13.dev8.dist-info → lfx_nightly-0.1.13.dev10.dist-info}/METADATA +1 -1
- {lfx_nightly-0.1.13.dev8.dist-info → lfx_nightly-0.1.13.dev10.dist-info}/RECORD +13 -13
- {lfx_nightly-0.1.13.dev8.dist-info → lfx_nightly-0.1.13.dev10.dist-info}/WHEEL +0 -0
- {lfx_nightly-0.1.13.dev8.dist-info → lfx_nightly-0.1.13.dev10.dist-info}/entry_points.txt +0 -0
lfx/components/agents/agent.py
CHANGED
|
@@ -20,7 +20,7 @@ from lfx.components.langchain_utilities.tool_calling import ToolCallingAgentComp
|
|
|
20
20
|
from lfx.custom.custom_component.component import get_component_toolkit
|
|
21
21
|
from lfx.custom.utils import update_component_build_config
|
|
22
22
|
from lfx.helpers.base_model import build_model_from_schema
|
|
23
|
-
from lfx.inputs.inputs import BoolInput
|
|
23
|
+
from lfx.inputs.inputs import BoolInput, SecretStrInput, StrInput
|
|
24
24
|
from lfx.io import DropdownInput, IntInput, MessageTextInput, MultilineInput, Output, TableInput
|
|
25
25
|
from lfx.log.logger import logger
|
|
26
26
|
from lfx.schema.data import Data
|
|
@@ -77,6 +77,32 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
77
77
|
},
|
|
78
78
|
},
|
|
79
79
|
),
|
|
80
|
+
SecretStrInput(
|
|
81
|
+
name="api_key",
|
|
82
|
+
display_name="API Key",
|
|
83
|
+
info="The API key to use for the model.",
|
|
84
|
+
required=True,
|
|
85
|
+
),
|
|
86
|
+
StrInput(
|
|
87
|
+
name="base_url",
|
|
88
|
+
display_name="Base URL",
|
|
89
|
+
info="The base URL of the API.",
|
|
90
|
+
required=True,
|
|
91
|
+
show=False,
|
|
92
|
+
),
|
|
93
|
+
StrInput(
|
|
94
|
+
name="project_id",
|
|
95
|
+
display_name="Project ID",
|
|
96
|
+
info="The project ID of the model.",
|
|
97
|
+
required=True,
|
|
98
|
+
show=False,
|
|
99
|
+
),
|
|
100
|
+
IntInput(
|
|
101
|
+
name="max_output_tokens",
|
|
102
|
+
display_name="Max Output Tokens",
|
|
103
|
+
info="The maximum number of tokens to generate.",
|
|
104
|
+
show=False,
|
|
105
|
+
),
|
|
80
106
|
*openai_inputs_filtered,
|
|
81
107
|
MultilineInput(
|
|
82
108
|
name="system_prompt",
|
|
@@ -195,10 +221,15 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
195
221
|
if not isinstance(self.tools, list): # type: ignore[has-type]
|
|
196
222
|
self.tools = []
|
|
197
223
|
current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)
|
|
224
|
+
|
|
198
225
|
if not isinstance(current_date_tool, StructuredTool):
|
|
199
226
|
msg = "CurrentDateComponent must be converted to a StructuredTool"
|
|
200
227
|
raise TypeError(msg)
|
|
201
228
|
self.tools.append(current_date_tool)
|
|
229
|
+
|
|
230
|
+
# Set shared callbacks for tracing the tools used by the agent
|
|
231
|
+
self.set_tools_callbacks(self.tools, self._get_shared_callbacks())
|
|
232
|
+
|
|
202
233
|
return llm_model, self.chat_history, self.tools
|
|
203
234
|
|
|
204
235
|
async def message_response(self) -> Message:
|
|
@@ -471,7 +502,8 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
471
502
|
def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:
|
|
472
503
|
"""Delete specified fields from build_config."""
|
|
473
504
|
for field in fields:
|
|
474
|
-
build_config
|
|
505
|
+
if build_config is not None and field in build_config:
|
|
506
|
+
build_config.pop(field, None)
|
|
475
507
|
|
|
476
508
|
def update_input_types(self, build_config: dotdict) -> dotdict:
|
|
477
509
|
"""Update input types for all fields in build_config."""
|
|
@@ -599,11 +631,14 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
599
631
|
agent_description = self.get_tool_description()
|
|
600
632
|
# TODO: Agent Description Depreciated Feature to be removed
|
|
601
633
|
description = f"{agent_description}{tools_names}"
|
|
634
|
+
|
|
602
635
|
tools = component_toolkit(component=self).get_tools(
|
|
603
636
|
tool_name="Call_Agent",
|
|
604
637
|
tool_description=description,
|
|
638
|
+
# here we do not use the shared callbacks as we are exposing the agent as a tool
|
|
605
639
|
callbacks=self.get_langchain_callbacks(),
|
|
606
640
|
)
|
|
607
641
|
if hasattr(self, "tools_metadata"):
|
|
608
642
|
tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)
|
|
643
|
+
|
|
609
644
|
return tools
|
lfx/components/ibm/watsonx.py
CHANGED
|
@@ -21,23 +21,24 @@ class WatsonxAIComponent(LCModelComponent):
|
|
|
21
21
|
beta = False
|
|
22
22
|
|
|
23
23
|
_default_models = ["ibm/granite-3-2b-instruct", "ibm/granite-3-8b-instruct", "ibm/granite-13b-instruct-v2"]
|
|
24
|
-
|
|
24
|
+
_urls = [
|
|
25
|
+
"https://us-south.ml.cloud.ibm.com",
|
|
26
|
+
"https://eu-de.ml.cloud.ibm.com",
|
|
27
|
+
"https://eu-gb.ml.cloud.ibm.com",
|
|
28
|
+
"https://au-syd.ml.cloud.ibm.com",
|
|
29
|
+
"https://jp-tok.ml.cloud.ibm.com",
|
|
30
|
+
"https://ca-tor.ml.cloud.ibm.com",
|
|
31
|
+
]
|
|
25
32
|
inputs = [
|
|
26
33
|
*LCModelComponent.get_base_inputs(),
|
|
27
34
|
DropdownInput(
|
|
28
|
-
name="
|
|
35
|
+
name="base_url",
|
|
29
36
|
display_name="watsonx API Endpoint",
|
|
30
37
|
info="The base URL of the API.",
|
|
31
|
-
value=
|
|
32
|
-
options=
|
|
33
|
-
"https://us-south.ml.cloud.ibm.com",
|
|
34
|
-
"https://eu-de.ml.cloud.ibm.com",
|
|
35
|
-
"https://eu-gb.ml.cloud.ibm.com",
|
|
36
|
-
"https://au-syd.ml.cloud.ibm.com",
|
|
37
|
-
"https://jp-tok.ml.cloud.ibm.com",
|
|
38
|
-
"https://ca-tor.ml.cloud.ibm.com",
|
|
39
|
-
],
|
|
38
|
+
value=[],
|
|
39
|
+
options=_urls,
|
|
40
40
|
real_time_refresh=True,
|
|
41
|
+
required=True,
|
|
41
42
|
),
|
|
42
43
|
StrInput(
|
|
43
44
|
name="project_id",
|
|
@@ -56,8 +57,9 @@ class WatsonxAIComponent(LCModelComponent):
|
|
|
56
57
|
display_name="Model Name",
|
|
57
58
|
options=[],
|
|
58
59
|
value=None,
|
|
59
|
-
|
|
60
|
+
real_time_refresh=True,
|
|
60
61
|
required=True,
|
|
62
|
+
refresh_button=True,
|
|
61
63
|
),
|
|
62
64
|
IntInput(
|
|
63
65
|
name="max_tokens",
|
|
@@ -155,18 +157,20 @@ class WatsonxAIComponent(LCModelComponent):
|
|
|
155
157
|
|
|
156
158
|
def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
|
|
157
159
|
"""Update model options when URL or API key changes."""
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if field_name == "url" and field_value:
|
|
160
|
+
if field_name == "base_url" and field_value:
|
|
161
161
|
try:
|
|
162
|
-
models = self.fetch_models(base_url=
|
|
163
|
-
build_config
|
|
164
|
-
if build_config
|
|
165
|
-
build_config
|
|
166
|
-
info_message = f"Updated model options: {len(models)} models found in {
|
|
162
|
+
models = self.fetch_models(base_url=field_value)
|
|
163
|
+
build_config["model_name"]["options"] = models
|
|
164
|
+
if build_config["model_name"]["value"]:
|
|
165
|
+
build_config["model_name"]["value"] = models[0]
|
|
166
|
+
info_message = f"Updated model options: {len(models)} models found in {field_value}"
|
|
167
167
|
logger.info(info_message)
|
|
168
168
|
except Exception: # noqa: BLE001
|
|
169
169
|
logger.exception("Error updating model options.")
|
|
170
|
+
if field_name == "model_name" and field_value and field_value in WatsonxAIComponent._urls:
|
|
171
|
+
build_config["model_name"]["options"] = self.fetch_models(base_url=field_value)
|
|
172
|
+
build_config["model_name"]["value"] = ""
|
|
173
|
+
return build_config
|
|
170
174
|
|
|
171
175
|
def build_model(self) -> LanguageModel:
|
|
172
176
|
# Parse logit_bias from JSON string if provided
|
|
@@ -195,7 +199,7 @@ class WatsonxAIComponent(LCModelComponent):
|
|
|
195
199
|
|
|
196
200
|
return ChatWatsonx(
|
|
197
201
|
apikey=SecretStr(self.api_key).get_secret_value(),
|
|
198
|
-
url=self.
|
|
202
|
+
url=self.base_url,
|
|
199
203
|
project_id=self.project_id,
|
|
200
204
|
model_id=self.model_name,
|
|
201
205
|
params=chat_params,
|
lfx/components/ollama/ollama.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
from contextlib import suppress
|
|
2
4
|
from typing import Any
|
|
3
5
|
from urllib.parse import urljoin
|
|
4
6
|
|
|
@@ -8,11 +10,27 @@ from langchain_ollama import ChatOllama
|
|
|
8
10
|
from lfx.base.models.model import LCModelComponent
|
|
9
11
|
from lfx.field_typing import LanguageModel
|
|
10
12
|
from lfx.field_typing.range_spec import RangeSpec
|
|
11
|
-
from lfx.
|
|
13
|
+
from lfx.helpers.base_model import build_model_from_schema
|
|
14
|
+
from lfx.io import (
|
|
15
|
+
BoolInput,
|
|
16
|
+
DictInput,
|
|
17
|
+
DropdownInput,
|
|
18
|
+
FloatInput,
|
|
19
|
+
IntInput,
|
|
20
|
+
MessageTextInput,
|
|
21
|
+
Output,
|
|
22
|
+
SecretStrInput,
|
|
23
|
+
SliderInput,
|
|
24
|
+
TableInput,
|
|
25
|
+
)
|
|
12
26
|
from lfx.log.logger import logger
|
|
27
|
+
from lfx.schema.data import Data
|
|
28
|
+
from lfx.schema.dataframe import DataFrame
|
|
29
|
+
from lfx.schema.table import EditMode
|
|
13
30
|
from lfx.utils.util import transform_localhost_url
|
|
14
31
|
|
|
15
32
|
HTTP_STATUS_OK = 200
|
|
33
|
+
TABLE_ROW_PLACEHOLDER = {"name": "field", "description": "description of field", "type": "str", "multiple": "False"}
|
|
16
34
|
|
|
17
35
|
|
|
18
36
|
class ChatOllamaComponent(LCModelComponent):
|
|
@@ -28,11 +46,51 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
28
46
|
DESIRED_CAPABILITY = "completion"
|
|
29
47
|
TOOL_CALLING_CAPABILITY = "tools"
|
|
30
48
|
|
|
49
|
+
# Define the table schema for the format input
|
|
50
|
+
TABLE_SCHEMA = [
|
|
51
|
+
{
|
|
52
|
+
"name": "name",
|
|
53
|
+
"display_name": "Name",
|
|
54
|
+
"type": "str",
|
|
55
|
+
"description": "Specify the name of the output field.",
|
|
56
|
+
"default": "field",
|
|
57
|
+
"edit_mode": EditMode.INLINE,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "description",
|
|
61
|
+
"display_name": "Description",
|
|
62
|
+
"type": "str",
|
|
63
|
+
"description": "Describe the purpose of the output field.",
|
|
64
|
+
"default": "description of field",
|
|
65
|
+
"edit_mode": EditMode.POPOVER,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "type",
|
|
69
|
+
"display_name": "Type",
|
|
70
|
+
"type": "str",
|
|
71
|
+
"edit_mode": EditMode.INLINE,
|
|
72
|
+
"description": ("Indicate the data type of the output field (e.g., str, int, float, bool, dict)."),
|
|
73
|
+
"options": ["str", "int", "float", "bool", "dict"],
|
|
74
|
+
"default": "str",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "multiple",
|
|
78
|
+
"display_name": "As List",
|
|
79
|
+
"type": "boolean",
|
|
80
|
+
"description": "Set to True if this output field should be a list of the specified type.",
|
|
81
|
+
"edit_mode": EditMode.INLINE,
|
|
82
|
+
"options": ["True", "False"],
|
|
83
|
+
"default": "False",
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
default_table_row = {row["name"]: row.get("default", None) for row in TABLE_SCHEMA}
|
|
87
|
+
default_table_row_schema = build_model_from_schema([default_table_row]).model_json_schema()
|
|
88
|
+
|
|
31
89
|
inputs = [
|
|
32
90
|
MessageTextInput(
|
|
33
91
|
name="base_url",
|
|
34
|
-
display_name="
|
|
35
|
-
info="Endpoint of the Ollama API. Defaults to http://localhost:11434
|
|
92
|
+
display_name="Ollama API URL",
|
|
93
|
+
info="Endpoint of the Ollama API. Defaults to http://localhost:11434.",
|
|
36
94
|
value="http://localhost:11434",
|
|
37
95
|
real_time_refresh=True,
|
|
38
96
|
),
|
|
@@ -44,6 +102,15 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
44
102
|
refresh_button=True,
|
|
45
103
|
real_time_refresh=True,
|
|
46
104
|
),
|
|
105
|
+
SecretStrInput(
|
|
106
|
+
name="api_key",
|
|
107
|
+
display_name="Ollama API Key",
|
|
108
|
+
info="Your Ollama API key.",
|
|
109
|
+
value=None,
|
|
110
|
+
required=False,
|
|
111
|
+
real_time_refresh=True,
|
|
112
|
+
advanced=True,
|
|
113
|
+
),
|
|
47
114
|
SliderInput(
|
|
48
115
|
name="temperature",
|
|
49
116
|
display_name="Temperature",
|
|
@@ -51,8 +118,13 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
51
118
|
range_spec=RangeSpec(min=0, max=1, step=0.01),
|
|
52
119
|
advanced=True,
|
|
53
120
|
),
|
|
54
|
-
|
|
55
|
-
name="format",
|
|
121
|
+
TableInput(
|
|
122
|
+
name="format",
|
|
123
|
+
display_name="Format",
|
|
124
|
+
info="Specify the format of the output.",
|
|
125
|
+
advanced=False,
|
|
126
|
+
table_schema=TABLE_SCHEMA,
|
|
127
|
+
value=default_table_row,
|
|
56
128
|
),
|
|
57
129
|
DictInput(name="metadata", display_name="Metadata", info="Metadata to add to the run trace.", advanced=True),
|
|
58
130
|
DropdownInput(
|
|
@@ -112,7 +184,12 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
112
184
|
name="top_k", display_name="Top K", info="Limits token selection to top K. (Default: 40)", advanced=True
|
|
113
185
|
),
|
|
114
186
|
FloatInput(name="top_p", display_name="Top P", info="Works together with top-k. (Default: 0.9)", advanced=True),
|
|
115
|
-
BoolInput(
|
|
187
|
+
BoolInput(
|
|
188
|
+
name="enable_verbose_output",
|
|
189
|
+
display_name="Ollama Verbose Output",
|
|
190
|
+
info="Whether to print out response text.",
|
|
191
|
+
advanced=True,
|
|
192
|
+
),
|
|
116
193
|
MessageTextInput(
|
|
117
194
|
name="tags",
|
|
118
195
|
display_name="Tags",
|
|
@@ -141,15 +218,22 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
141
218
|
*LCModelComponent.get_base_inputs(),
|
|
142
219
|
]
|
|
143
220
|
|
|
221
|
+
outputs = [
|
|
222
|
+
Output(display_name="Text", name="text_output", method="text_response"),
|
|
223
|
+
Output(display_name="Language Model", name="model_output", method="build_model"),
|
|
224
|
+
Output(display_name="Data", name="data_output", method="build_data_output"),
|
|
225
|
+
Output(display_name="DataFrame", name="dataframe_output", method="build_dataframe_output"),
|
|
226
|
+
]
|
|
227
|
+
|
|
144
228
|
def build_model(self) -> LanguageModel: # type: ignore[type-var]
|
|
145
229
|
# Mapping mirostat settings to their corresponding values
|
|
146
230
|
mirostat_options = {"Mirostat": 1, "Mirostat 2.0": 2}
|
|
147
231
|
|
|
148
|
-
# Default to
|
|
149
|
-
mirostat_value = mirostat_options.get(self.mirostat,
|
|
232
|
+
# Default to None for 'Disabled'
|
|
233
|
+
mirostat_value = mirostat_options.get(self.mirostat, None)
|
|
150
234
|
|
|
151
235
|
# Set mirostat_eta and mirostat_tau to None if mirostat is disabled
|
|
152
|
-
if mirostat_value
|
|
236
|
+
if mirostat_value is None:
|
|
153
237
|
mirostat_eta = None
|
|
154
238
|
mirostat_tau = None
|
|
155
239
|
else:
|
|
@@ -169,12 +253,18 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
169
253
|
"Learn more at https://docs.ollama.com/openai#openai-compatibility"
|
|
170
254
|
)
|
|
171
255
|
|
|
256
|
+
try:
|
|
257
|
+
output_format = self._parse_format_field(self.format)
|
|
258
|
+
except Exception as e:
|
|
259
|
+
msg = f"Failed to parse the format field: {e}"
|
|
260
|
+
raise ValueError(msg) from e
|
|
261
|
+
|
|
172
262
|
# Mapping system settings to their corresponding values
|
|
173
263
|
llm_params = {
|
|
174
264
|
"base_url": transformed_base_url,
|
|
175
265
|
"model": self.model_name,
|
|
176
266
|
"mirostat": mirostat_value,
|
|
177
|
-
"format":
|
|
267
|
+
"format": output_format,
|
|
178
268
|
"metadata": self.metadata,
|
|
179
269
|
"tags": self.tags.split(",") if self.tags else None,
|
|
180
270
|
"mirostat_eta": mirostat_eta,
|
|
@@ -191,9 +281,12 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
191
281
|
"timeout": self.timeout or None,
|
|
192
282
|
"top_k": self.top_k or None,
|
|
193
283
|
"top_p": self.top_p or None,
|
|
194
|
-
"verbose": self.
|
|
284
|
+
"verbose": self.enable_verbose_output or False,
|
|
195
285
|
"template": self.template,
|
|
196
286
|
}
|
|
287
|
+
headers = self.headers
|
|
288
|
+
if headers is not None:
|
|
289
|
+
llm_params["client_kwargs"] = {"headers": headers}
|
|
197
290
|
|
|
198
291
|
# Remove parameters with None values
|
|
199
292
|
llm_params = {k: v for k, v in llm_params.items() if v is not None}
|
|
@@ -219,7 +312,9 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
219
312
|
url = url.rstrip("/").removesuffix("/v1")
|
|
220
313
|
if not url.endswith("/"):
|
|
221
314
|
url = url + "/"
|
|
222
|
-
return (
|
|
315
|
+
return (
|
|
316
|
+
await client.get(url=urljoin(url, "api/tags"), headers=self.headers)
|
|
317
|
+
).status_code == HTTP_STATUS_OK
|
|
223
318
|
except httpx.RequestError:
|
|
224
319
|
return False
|
|
225
320
|
|
|
@@ -292,8 +387,9 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
292
387
|
show_url = urljoin(base_url, "api/show")
|
|
293
388
|
|
|
294
389
|
async with httpx.AsyncClient() as client:
|
|
390
|
+
headers = self.headers
|
|
295
391
|
# Fetch available models
|
|
296
|
-
tags_response = await client.get(tags_url)
|
|
392
|
+
tags_response = await client.get(url=tags_url, headers=headers)
|
|
297
393
|
tags_response.raise_for_status()
|
|
298
394
|
models = tags_response.json()
|
|
299
395
|
if asyncio.iscoroutine(models):
|
|
@@ -307,11 +403,12 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
307
403
|
await logger.adebug(f"Checking model: {model_name}")
|
|
308
404
|
|
|
309
405
|
payload = {"model": model_name}
|
|
310
|
-
show_response = await client.post(show_url, json=payload)
|
|
406
|
+
show_response = await client.post(url=show_url, json=payload, headers=headers)
|
|
311
407
|
show_response.raise_for_status()
|
|
312
408
|
json_data = show_response.json()
|
|
313
409
|
if asyncio.iscoroutine(json_data):
|
|
314
410
|
json_data = await json_data
|
|
411
|
+
|
|
315
412
|
capabilities = json_data.get(self.JSON_CAPABILITIES_KEY, [])
|
|
316
413
|
await logger.adebug(f"Model: {model_name}, Capabilities: {capabilities}")
|
|
317
414
|
|
|
@@ -325,3 +422,113 @@ class ChatOllamaComponent(LCModelComponent):
|
|
|
325
422
|
raise ValueError(msg) from e
|
|
326
423
|
|
|
327
424
|
return model_ids
|
|
425
|
+
|
|
426
|
+
def _parse_format_field(self, format_value: Any) -> Any:
|
|
427
|
+
"""Parse the format field to handle both string and dict inputs.
|
|
428
|
+
|
|
429
|
+
The format field can be:
|
|
430
|
+
- A simple string like "json" (backward compatibility)
|
|
431
|
+
- A JSON string from NestedDictInput that needs parsing
|
|
432
|
+
- A dict/JSON schema (already parsed)
|
|
433
|
+
- None or empty
|
|
434
|
+
|
|
435
|
+
Args:
|
|
436
|
+
format_value: The raw format value from the input field
|
|
437
|
+
|
|
438
|
+
Returns:
|
|
439
|
+
Parsed format value as string, dict, or None
|
|
440
|
+
"""
|
|
441
|
+
if not format_value:
|
|
442
|
+
return None
|
|
443
|
+
|
|
444
|
+
schema = format_value
|
|
445
|
+
if isinstance(format_value, list):
|
|
446
|
+
schema = build_model_from_schema(format_value).model_json_schema()
|
|
447
|
+
if schema == self.default_table_row_schema:
|
|
448
|
+
return None # the rows are generic placeholder rows
|
|
449
|
+
elif isinstance(format_value, str): # parse as json if string
|
|
450
|
+
with suppress(json.JSONDecodeError): # e.g., literal "json" is valid for format field
|
|
451
|
+
schema = json.loads(format_value)
|
|
452
|
+
|
|
453
|
+
return schema or None
|
|
454
|
+
|
|
455
|
+
async def _parse_json_response(self) -> Any:
|
|
456
|
+
"""Parse the JSON response from the model.
|
|
457
|
+
|
|
458
|
+
This method gets the text response and attempts to parse it as JSON.
|
|
459
|
+
Works with models that have format='json' or a JSON schema set.
|
|
460
|
+
|
|
461
|
+
Returns:
|
|
462
|
+
Parsed JSON (dict, list, or primitive type)
|
|
463
|
+
|
|
464
|
+
Raises:
|
|
465
|
+
ValueError: If the response is not valid JSON
|
|
466
|
+
"""
|
|
467
|
+
message = await self.text_response()
|
|
468
|
+
text = message.text if hasattr(message, "text") else str(message)
|
|
469
|
+
|
|
470
|
+
if not text:
|
|
471
|
+
msg = "No response from model"
|
|
472
|
+
raise ValueError(msg)
|
|
473
|
+
|
|
474
|
+
try:
|
|
475
|
+
return json.loads(text)
|
|
476
|
+
except json.JSONDecodeError as e:
|
|
477
|
+
msg = f"Invalid JSON response. Ensure model supports JSON output. Error: {e}"
|
|
478
|
+
raise ValueError(msg) from e
|
|
479
|
+
|
|
480
|
+
async def build_data_output(self) -> Data:
|
|
481
|
+
"""Build a Data output from the model's JSON response.
|
|
482
|
+
|
|
483
|
+
Returns:
|
|
484
|
+
Data: A Data object containing the parsed JSON response
|
|
485
|
+
"""
|
|
486
|
+
parsed = await self._parse_json_response()
|
|
487
|
+
|
|
488
|
+
# If the response is already a dict, wrap it in Data
|
|
489
|
+
if isinstance(parsed, dict):
|
|
490
|
+
return Data(data=parsed)
|
|
491
|
+
|
|
492
|
+
# If it's a list, wrap in a results container
|
|
493
|
+
if isinstance(parsed, list):
|
|
494
|
+
if len(parsed) == 1:
|
|
495
|
+
return Data(data=parsed[0])
|
|
496
|
+
return Data(data={"results": parsed})
|
|
497
|
+
|
|
498
|
+
# For primitive types, wrap in a value container
|
|
499
|
+
return Data(data={"value": parsed})
|
|
500
|
+
|
|
501
|
+
async def build_dataframe_output(self) -> DataFrame:
|
|
502
|
+
"""Build a DataFrame output from the model's JSON response.
|
|
503
|
+
|
|
504
|
+
Returns:
|
|
505
|
+
DataFrame: A DataFrame containing the parsed JSON response
|
|
506
|
+
|
|
507
|
+
Raises:
|
|
508
|
+
ValueError: If the response cannot be converted to a DataFrame
|
|
509
|
+
"""
|
|
510
|
+
parsed = await self._parse_json_response()
|
|
511
|
+
|
|
512
|
+
# If it's a list of dicts, convert directly to DataFrame
|
|
513
|
+
if isinstance(parsed, list):
|
|
514
|
+
if not parsed:
|
|
515
|
+
return DataFrame()
|
|
516
|
+
# Ensure all items are dicts for proper DataFrame conversion
|
|
517
|
+
if all(isinstance(item, dict) for item in parsed):
|
|
518
|
+
return DataFrame(parsed)
|
|
519
|
+
msg = "List items must be dictionaries to convert to DataFrame"
|
|
520
|
+
raise ValueError(msg)
|
|
521
|
+
|
|
522
|
+
# If it's a single dict, wrap in a list to create a single-row DataFrame
|
|
523
|
+
if isinstance(parsed, dict):
|
|
524
|
+
return DataFrame([parsed])
|
|
525
|
+
|
|
526
|
+
# For primitive types, create a single-column DataFrame
|
|
527
|
+
return DataFrame([{"value": parsed}])
|
|
528
|
+
|
|
529
|
+
@property
|
|
530
|
+
def headers(self) -> dict[str, str] | None:
|
|
531
|
+
"""Get the headers for the Ollama API."""
|
|
532
|
+
if self.api_key and self.api_key.strip():
|
|
533
|
+
return {"Authorization": f"Bearer {self.api_key}"}
|
|
534
|
+
return None
|
lfx/schema/schema.py
CHANGED
|
@@ -149,6 +149,11 @@ class InputValueRequest(BaseModel):
|
|
|
149
149
|
description="Defines on which components the input value should be applied. "
|
|
150
150
|
"'any' applies to all input components.",
|
|
151
151
|
)
|
|
152
|
+
client_request_time: int | None = Field(
|
|
153
|
+
None,
|
|
154
|
+
description="Client-side timestamp in milliseconds when the request was initiated. "
|
|
155
|
+
"Used to calculate accurate end-to-end duration.",
|
|
156
|
+
)
|
|
152
157
|
|
|
153
158
|
# add an example
|
|
154
159
|
model_config = ConfigDict(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lfx-nightly
|
|
3
|
-
Version: 0.1.13.
|
|
3
|
+
Version: 0.1.13.dev10
|
|
4
4
|
Summary: Langflow Executor - A lightweight CLI tool for executing and serving Langflow AI flows
|
|
5
5
|
Author-email: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
|
|
6
6
|
Requires-Python: <3.14,>=3.10
|
|
@@ -4,16 +4,16 @@ lfx/constants.py,sha256=Ert_SpwXhutgcTKEvtDArtkONXgyE5x68opMoQfukMA,203
|
|
|
4
4
|
lfx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
lfx/settings.py,sha256=wnx4zkOLQ8mvampYsnnvVV9GvEnRUuWQpKFSbFTCIp4,181
|
|
6
6
|
lfx/type_extraction.py,sha256=eCZNl9nAQivKdaPv_9BK71N0JV9Rtr--veAht0dnQ4A,2921
|
|
7
|
-
lfx/_assets/component_index.json,sha256=
|
|
7
|
+
lfx/_assets/component_index.json,sha256=zHM0opm5e8efaCHaiGBVeICiycRH9Gs1MqBZOgk9ves,3572362
|
|
8
8
|
lfx/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
lfx/base/constants.py,sha256=v9vo0Ifg8RxDu__XqgGzIXHlsnUFyWM-SSux0uHHoz8,1187
|
|
10
10
|
lfx/base/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
lfx/base/agents/agent.py,sha256=
|
|
11
|
+
lfx/base/agents/agent.py,sha256=uKp5OSNxGbKa-fyZLfHl68f1ZntS49LFLNN49OGcnnY,15199
|
|
12
12
|
lfx/base/agents/callback.py,sha256=mjlT9ukBMVrfjYrHsJowqpY4g9hVGBVBIYhncLWr3tQ,3692
|
|
13
13
|
lfx/base/agents/context.py,sha256=u0wboX1aRR22Ia8gY14WF12RjhE0Rxv9hPBiixT9DtQ,3916
|
|
14
14
|
lfx/base/agents/default_prompts.py,sha256=tUjfczwt4D5R1KozNOl1uSL2V2rSCZeUMS-cfV4Gwn0,955
|
|
15
15
|
lfx/base/agents/errors.py,sha256=4QY1AqSWZaOjq-iQRYH_aeCfH_hWECLQkiwybNXz66U,531
|
|
16
|
-
lfx/base/agents/events.py,sha256=
|
|
16
|
+
lfx/base/agents/events.py,sha256=wk5sEsAkFbZxx_UUYYSvzWwocmAQZzfFlxKVAb_QSQ8,17170
|
|
17
17
|
lfx/base/agents/utils.py,sha256=VEAVYC6oOadjKeZ-cUS-1OOCnWW69FhpcGWzjvR4uZ8,7161
|
|
18
18
|
lfx/base/agents/crewai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
lfx/base/agents/crewai/crew.py,sha256=TN1JyLXMpJc2yPH3tokhFmxKKYoJ4lMvmG19DmpKfeY,7953
|
|
@@ -69,11 +69,11 @@ lfx/base/models/google_generative_ai_constants.py,sha256=EuFd77ZrrSr6YtSKtmEaq0N
|
|
|
69
69
|
lfx/base/models/google_generative_ai_model.py,sha256=wEIyBkTZcZD3akUiAKTGxazTJnOQeh80WHMKiHdK1wo,1839
|
|
70
70
|
lfx/base/models/groq_constants.py,sha256=WOMpYRwJVrZavsi7zGJwRHJX8ZBvdtILUOmBFv0QIPQ,5536
|
|
71
71
|
lfx/base/models/model.py,sha256=nJgExAvMJ5WMxCqC__Jc1GdkgJag4yrwC9nFtPEVupM,15324
|
|
72
|
-
lfx/base/models/model_input_constants.py,sha256=
|
|
72
|
+
lfx/base/models/model_input_constants.py,sha256=XDG0xYKmPbxUWUXCtj5b7-5w2b3Wupez4mY-jAr_coI,12893
|
|
73
73
|
lfx/base/models/model_metadata.py,sha256=tNFPiRqBJ0WPKdNEqBxuoKk0n8H_h0J--bCV5pk9k4o,1325
|
|
74
74
|
lfx/base/models/model_utils.py,sha256=RwXUSIw5gdRakQ-VGbLI1iT0CeeWrVSNTgUQIrrc6uE,474
|
|
75
75
|
lfx/base/models/novita_constants.py,sha256=_mgBYGwpddUw4CLhLKJl-psOUzA_SQGHrfZJUNes6aI,1247
|
|
76
|
-
lfx/base/models/ollama_constants.py,sha256=
|
|
76
|
+
lfx/base/models/ollama_constants.py,sha256=NixN5DIrmZdz4WqGA2li_PLHYDuWl2D90zWCHxavWaM,1021
|
|
77
77
|
lfx/base/models/openai_constants.py,sha256=DSlnUjmtb6KXQNDifxop4VVQPvB1Y9vftK6ZmFiudf4,4798
|
|
78
78
|
lfx/base/models/sambanova_constants.py,sha256=mYPF7vUbMow9l4jQ2OJrIkAJhGs3fGWTCVNfG3oQZTc,519
|
|
79
79
|
lfx/base/models/watsonx_constants.py,sha256=lR0hOxcrQwHSMTH_49fmYlGJJb6KEeeyoUeXK8PUBf4,792
|
|
@@ -116,7 +116,7 @@ lfx/components/Notion/update_page_property.py,sha256=tgmPMbD1eX58dQQNXv1w5FzDec7
|
|
|
116
116
|
lfx/components/agentql/__init__.py,sha256=Erl669Dzsk-SegsDPWTtkKbprMXVuv8UTCo5REzZGTc,56
|
|
117
117
|
lfx/components/agentql/agentql_api.py,sha256=N94yEK7ZuQCIsFBlr_8dqrJY-K1-KNb6QEEYfDIsDME,5569
|
|
118
118
|
lfx/components/agents/__init__.py,sha256=O5ng90Dn9mSlpCdeGPXM4tvdWYVfEMv_7PGDKShyBKg,1294
|
|
119
|
-
lfx/components/agents/agent.py,sha256
|
|
119
|
+
lfx/components/agents/agent.py,sha256=rfczlpKAoTuGDIhJWDQU7GZSXrT1uJbjD-540TakFKU,28103
|
|
120
120
|
lfx/components/agents/altk_agent.py,sha256=D_ChOwqYao0QZBfiLpiMVoMOgCwzcb_q0MIPDULLHW8,15939
|
|
121
121
|
lfx/components/agents/cuga_agent.py,sha256=JNi4MsSziTJQI3z_0KGzNWxm5RDaMk_W9zcTW2KcTtI,44499
|
|
122
122
|
lfx/components/agents/mcp_component.py,sha256=gbEzi-hZMqVmIGO5DjJDOlmpisPkylOSZSGgaDjiQLY,26809
|
|
@@ -338,7 +338,7 @@ lfx/components/huggingface/__init__.py,sha256=b8NFo5-9zbBY4f9UVMzzQ9GdnSGqHYRKSW
|
|
|
338
338
|
lfx/components/huggingface/huggingface.py,sha256=up18KIWd__v1wjKe6Ee4jzFZ3pzYao6RIRRICTFXlEc,7621
|
|
339
339
|
lfx/components/huggingface/huggingface_inference_api.py,sha256=rwVGZYl0uE-AEeSwMOmnBqc1i-973atZCr2IhX-yVY4,4243
|
|
340
340
|
lfx/components/ibm/__init__.py,sha256=Jz5-Fc7fG2rW5qeHEJ1z9KfFkItpuINKBu-D4HaT-uc,1094
|
|
341
|
-
lfx/components/ibm/watsonx.py,sha256=
|
|
341
|
+
lfx/components/ibm/watsonx.py,sha256=M2Ai4KDSJFy2VI9evLTr5fYn67eyMxJQpXl64xedQp0,7940
|
|
342
342
|
lfx/components/ibm/watsonx_embeddings.py,sha256=_97UE-qQDCjkWfX3NFWNCti4TUXxO1LO0FIBQnFW4Co,4824
|
|
343
343
|
lfx/components/icosacomputing/__init__.py,sha256=NByWM-IMPf7N1lOeZDet8CvIa8A25kG3yKircYwS52w,120
|
|
344
344
|
lfx/components/icosacomputing/combinatorial_reasoner.py,sha256=SFVwR_8jGHVDaGO81jj2vzzeKh892h1nMGxCDljbvNY,2766
|
|
@@ -435,7 +435,7 @@ lfx/components/nvidia/system_assist.py,sha256=G8cgsLQxRBBnUt49_Uzxt7cdTNplVAzUlD
|
|
|
435
435
|
lfx/components/olivya/__init__.py,sha256=ilZR88huL3vnQHO27g4jsUkyIYSgN7RPOq8Corbi6xA,67
|
|
436
436
|
lfx/components/olivya/olivya.py,sha256=PDmsn8dBdSwAZUM2QGTyTwxGWsINCKaYR4yTjE-4lIQ,4192
|
|
437
437
|
lfx/components/ollama/__init__.py,sha256=fau8QcWs_eHO2MmtQ4coiKj9CzFA9X4hqFf541ekgXk,1068
|
|
438
|
-
lfx/components/ollama/ollama.py,sha256=
|
|
438
|
+
lfx/components/ollama/ollama.py,sha256=1yhL2dDoeOEikhP2bjx6jc8p4B-uCGFQiyyhSk40Ruk,21238
|
|
439
439
|
lfx/components/ollama/ollama_embeddings.py,sha256=nvg-JQvue6j7tcrbbPeq1U_-LUj1MKawWbXxnnvJlWM,3976
|
|
440
440
|
lfx/components/openai/__init__.py,sha256=G4Fgw4pmmDohdIOmzaeSCGijzKjyqFXNJPLwlcUDZ3w,1113
|
|
441
441
|
lfx/components/openai/openai.py,sha256=imWO1tTJ0tTLqax1v5bNBPCRINTj2f2wN8j5G-a07GI,4505
|
|
@@ -658,7 +658,7 @@ lfx/schema/log.py,sha256=TISQa44D4pL_-AOw9p0nOPV-7s6Phl-0yrpuZihhEsU,1981
|
|
|
658
658
|
lfx/schema/message.py,sha256=U4vtgkC6lNciJbfwtrIquyB3-UdPieHAjuegGk8416E,18506
|
|
659
659
|
lfx/schema/openai_responses_schemas.py,sha256=drMCAlliefHfGRojBTMepPwk4DyEGh67naWvMPD10Sw,2596
|
|
660
660
|
lfx/schema/properties.py,sha256=ZRY6FUDfqpc5wQ-bi-ZuUUrusF9t-pt9fQa_FNPpia0,1356
|
|
661
|
-
lfx/schema/schema.py,sha256=
|
|
661
|
+
lfx/schema/schema.py,sha256=WkwdKNbtnHlh4GhQANXuxHRyS9SAXnTPd7KFhsGIoiU,5296
|
|
662
662
|
lfx/schema/serialize.py,sha256=Y7aL91w3BW4ZYkgdIHosUYdpIJUDku-SoqYoIQtwtGM,252
|
|
663
663
|
lfx/schema/table.py,sha256=1RdMmk1vbzmPFW0JEGhP7WDDRtvUKH9lkDw5v-JWhSw,4668
|
|
664
664
|
lfx/schema/validators.py,sha256=1CC4jU3sFmPnauie_U_Xb_QpcnsBf3XT7oWphr5Lt8U,4023
|
|
@@ -730,7 +730,7 @@ lfx/utils/schemas.py,sha256=NbOtVQBrn4d0BAu-0H_eCTZI2CXkKZlRY37XCSmuJwc,3865
|
|
|
730
730
|
lfx/utils/util.py,sha256=Ww85wbr1-vjh2pXVtmTqoUVr6MXAW8S7eDx_Ys6HpE8,20696
|
|
731
731
|
lfx/utils/util_strings.py,sha256=nU_IcdphNaj6bAPbjeL-c1cInQPfTBit8mp5Y57lwQk,1686
|
|
732
732
|
lfx/utils/version.py,sha256=cHpbO0OJD2JQAvVaTH_6ibYeFbHJV0QDHs_YXXZ-bT8,671
|
|
733
|
-
lfx_nightly-0.1.13.
|
|
734
|
-
lfx_nightly-0.1.13.
|
|
735
|
-
lfx_nightly-0.1.13.
|
|
736
|
-
lfx_nightly-0.1.13.
|
|
733
|
+
lfx_nightly-0.1.13.dev10.dist-info/METADATA,sha256=zAEy_d1dQWrDneWNhhmrFz20gFgfoGE7k_3FgKKB7Yk,8290
|
|
734
|
+
lfx_nightly-0.1.13.dev10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
735
|
+
lfx_nightly-0.1.13.dev10.dist-info/entry_points.txt,sha256=1724p3RHDQRT2CKx_QRzEIa7sFuSVO0Ux70YfXfoMT4,42
|
|
736
|
+
lfx_nightly-0.1.13.dev10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|