lfx-nightly 0.1.12.dev34__py3-none-any.whl → 0.1.12.dev36__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/base/composio/composio_base.py +65 -26
- lfx/base/data/base_file.py +3 -2
- lfx/base/tools/flow_tool.py +1 -1
- lfx/base/tools/run_flow.py +1 -1
- lfx/cli/commands.py +17 -12
- lfx/cli/run.py +156 -95
- lfx/components/__init__.py +3 -0
- lfx/components/deactivated/sub_flow.py +1 -1
- lfx/components/logic/flow_tool.py +1 -1
- lfx/components/logic/run_flow.py +1 -1
- lfx/components/logic/sub_flow.py +1 -1
- lfx/components/vectorstores/local_db.py +0 -1
- lfx/components/vlmrun/__init__.py +34 -0
- lfx/components/vlmrun/vlmrun_transcription.py +224 -0
- lfx/custom/custom_component/custom_component.py +1 -1
- lfx/graph/vertex/param_handler.py +2 -2
- lfx/helpers/__init__.py +129 -1
- lfx/helpers/flow.py +0 -3
- lfx/inputs/input_mixin.py +2 -1
- lfx/inputs/inputs.py +5 -14
- lfx/log/logger.py +5 -1
- lfx/memory/__init__.py +10 -30
- lfx/schema/cross_module.py +80 -0
- lfx/schema/data.py +2 -1
- lfx/services/mcp_composer/service.py +3 -2
- lfx/services/settings/base.py +31 -0
- lfx/utils/langflow_utils.py +52 -0
- {lfx_nightly-0.1.12.dev34.dist-info → lfx_nightly-0.1.12.dev36.dist-info}/METADATA +1 -1
- {lfx_nightly-0.1.12.dev34.dist-info → lfx_nightly-0.1.12.dev36.dist-info}/RECORD +31 -27
- {lfx_nightly-0.1.12.dev34.dist-info → lfx_nightly-0.1.12.dev36.dist-info}/WHEEL +0 -0
- {lfx_nightly-0.1.12.dev34.dist-info → lfx_nightly-0.1.12.dev36.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import json
|
|
3
3
|
import re
|
|
4
|
+
from contextlib import suppress
|
|
4
5
|
from typing import Any
|
|
5
6
|
|
|
6
7
|
from composio import Composio
|
|
@@ -381,9 +382,9 @@ class ComposioBaseComponent(Component):
|
|
|
381
382
|
if clean_field == "user_id":
|
|
382
383
|
clean_field = f"{self.app_name}_user_id"
|
|
383
384
|
|
|
384
|
-
# Handle reserved attribute name conflicts (e.g., 'status'
|
|
385
|
-
#
|
|
386
|
-
if clean_field in {"status"}:
|
|
385
|
+
# Handle reserved attribute name conflicts (e.g., 'status', 'name')
|
|
386
|
+
# Prefix with app name to prevent clashes with component attributes
|
|
387
|
+
if clean_field in {"status", "name"}:
|
|
387
388
|
clean_field = f"{self.app_name}_{clean_field}"
|
|
388
389
|
|
|
389
390
|
action_fields.append(clean_field)
|
|
@@ -549,6 +550,13 @@ class ComposioBaseComponent(Component):
|
|
|
549
550
|
field_schema_copy["description"] = f"Status for {self.app_name.title()}: " + field_schema.get(
|
|
550
551
|
"description", ""
|
|
551
552
|
)
|
|
553
|
+
elif clean_field_name == "name":
|
|
554
|
+
clean_field_name = f"{self.app_name}_name"
|
|
555
|
+
# Update the field schema description to reflect the name change
|
|
556
|
+
field_schema_copy = field_schema.copy()
|
|
557
|
+
field_schema_copy["description"] = f"Name for {self.app_name.title()}: " + field_schema.get(
|
|
558
|
+
"description", ""
|
|
559
|
+
)
|
|
552
560
|
else:
|
|
553
561
|
# Use the original field schema for all other fields
|
|
554
562
|
field_schema_copy = field_schema
|
|
@@ -571,7 +579,17 @@ class ComposioBaseComponent(Component):
|
|
|
571
579
|
|
|
572
580
|
# Also update required fields to match cleaned names
|
|
573
581
|
if flat_schema.get("required"):
|
|
574
|
-
cleaned_required = [
|
|
582
|
+
cleaned_required = []
|
|
583
|
+
for field in flat_schema["required"]:
|
|
584
|
+
base = field.replace("[0]", "")
|
|
585
|
+
if base == "user_id":
|
|
586
|
+
cleaned_required.append(f"{self.app_name}_user_id")
|
|
587
|
+
elif base == "status":
|
|
588
|
+
cleaned_required.append(f"{self.app_name}_status")
|
|
589
|
+
elif base == "name":
|
|
590
|
+
cleaned_required.append(f"{self.app_name}_name")
|
|
591
|
+
else:
|
|
592
|
+
cleaned_required.append(base)
|
|
575
593
|
flat_schema["required"] = cleaned_required
|
|
576
594
|
|
|
577
595
|
input_schema = create_input_schema_from_json_schema(flat_schema)
|
|
@@ -756,6 +774,9 @@ class ComposioBaseComponent(Component):
|
|
|
756
774
|
# Ensure _all_fields includes new ones
|
|
757
775
|
self._all_fields.update({i.name for i in lf_inputs if i.name is not None})
|
|
758
776
|
|
|
777
|
+
# Normalize input_types to prevent None values
|
|
778
|
+
self.update_input_types(build_config)
|
|
779
|
+
|
|
759
780
|
def _is_tool_mode_enabled(self) -> bool:
|
|
760
781
|
"""Check if tool_mode is currently enabled."""
|
|
761
782
|
return getattr(self, "tool_mode", False)
|
|
@@ -1094,6 +1115,20 @@ class ComposioBaseComponent(Component):
|
|
|
1094
1115
|
# Also clear any tracked dynamic fields
|
|
1095
1116
|
self._clear_auth_dynamic_fields(build_config)
|
|
1096
1117
|
|
|
1118
|
+
def update_input_types(self, build_config: dict) -> dict:
|
|
1119
|
+
"""Normalize input_types to [] wherever None appears in the build_config template."""
|
|
1120
|
+
try:
|
|
1121
|
+
for key, value in list(build_config.items()):
|
|
1122
|
+
if isinstance(value, dict):
|
|
1123
|
+
if value.get("input_types") is None:
|
|
1124
|
+
build_config[key]["input_types"] = []
|
|
1125
|
+
elif hasattr(value, "input_types") and value.input_types is None:
|
|
1126
|
+
with suppress(AttributeError, TypeError):
|
|
1127
|
+
value.input_types = []
|
|
1128
|
+
except (RuntimeError, KeyError):
|
|
1129
|
+
pass
|
|
1130
|
+
return build_config
|
|
1131
|
+
|
|
1097
1132
|
def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:
|
|
1098
1133
|
"""Update build config for auth and action selection."""
|
|
1099
1134
|
# Avoid normalizing legacy input_types here; rely on upstream fixes
|
|
@@ -1233,7 +1268,7 @@ class ComposioBaseComponent(Component):
|
|
|
1233
1268
|
build_config["auth_link"].pop("connection_id", None)
|
|
1234
1269
|
build_config["action_button"]["helper_text"] = "Please connect before selecting actions."
|
|
1235
1270
|
build_config["action_button"]["helper_text_metadata"] = {"variant": "destructive"}
|
|
1236
|
-
return build_config
|
|
1271
|
+
return self.update_input_types(build_config)
|
|
1237
1272
|
|
|
1238
1273
|
# Handle auth mode change -> render appropriate fields based on schema
|
|
1239
1274
|
if field_name == "auth_mode":
|
|
@@ -1290,7 +1325,7 @@ class ComposioBaseComponent(Component):
|
|
|
1290
1325
|
}
|
|
1291
1326
|
build_config["action_button"]["helper_text"] = ""
|
|
1292
1327
|
build_config["action_button"]["helper_text_metadata"] = {}
|
|
1293
|
-
return build_config
|
|
1328
|
+
return self.update_input_types(build_config)
|
|
1294
1329
|
if mode:
|
|
1295
1330
|
managed = schema.get("composio_managed_auth_schemes") or []
|
|
1296
1331
|
# Always hide the Create Auth Config control (used internally only)
|
|
@@ -1306,7 +1341,7 @@ class ComposioBaseComponent(Component):
|
|
|
1306
1341
|
else:
|
|
1307
1342
|
# Custom → render only required fields based on the toolkit schema
|
|
1308
1343
|
self._render_custom_auth_fields(build_config, schema, mode)
|
|
1309
|
-
return build_config
|
|
1344
|
+
return self.update_input_types(build_config)
|
|
1310
1345
|
|
|
1311
1346
|
# Handle connection initiation when tool mode is enabled
|
|
1312
1347
|
if field_name == "auth_link" and isinstance(field_value, dict):
|
|
@@ -1323,7 +1358,7 @@ class ComposioBaseComponent(Component):
|
|
|
1323
1358
|
build_config["action_button"]["helper_text"] = ""
|
|
1324
1359
|
build_config["action_button"]["helper_text_metadata"] = {}
|
|
1325
1360
|
logger.info(f"Using existing ACTIVE connection {connection_id} for {toolkit_slug}")
|
|
1326
|
-
return build_config
|
|
1361
|
+
return self.update_input_types(build_config)
|
|
1327
1362
|
|
|
1328
1363
|
# Only reuse ACTIVE connections; otherwise create a new connection
|
|
1329
1364
|
stored_connection_id = None
|
|
@@ -1342,11 +1377,11 @@ class ComposioBaseComponent(Component):
|
|
|
1342
1377
|
redirect_url, connection_id = self._initiate_connection(toolkit_slug)
|
|
1343
1378
|
build_config["auth_link"]["value"] = redirect_url
|
|
1344
1379
|
logger.info(f"New OAuth URL created for {toolkit_slug}: {redirect_url}")
|
|
1345
|
-
return build_config
|
|
1380
|
+
return self.update_input_types(build_config)
|
|
1346
1381
|
if not mode:
|
|
1347
1382
|
build_config["auth_link"]["value"] = "connect"
|
|
1348
1383
|
build_config["auth_link"]["auth_tooltip"] = "Select Auth Mode"
|
|
1349
|
-
return build_config
|
|
1384
|
+
return self.update_input_types(build_config)
|
|
1350
1385
|
# Custom modes: create auth config and/or initiate with config
|
|
1351
1386
|
# Validate required fields before creating any auth config
|
|
1352
1387
|
required_missing = []
|
|
@@ -1403,7 +1438,7 @@ class ComposioBaseComponent(Component):
|
|
|
1403
1438
|
build_config["auth_mode"]["helper_text_metadata"] = {"variant": "destructive"}
|
|
1404
1439
|
build_config["auth_link"]["value"] = "connect"
|
|
1405
1440
|
build_config["auth_link"]["auth_tooltip"] = f"Missing: {missing_joined}"
|
|
1406
|
-
return build_config
|
|
1441
|
+
return self.update_input_types(build_config)
|
|
1407
1442
|
composio = self._build_wrapper()
|
|
1408
1443
|
if mode == "OAUTH2":
|
|
1409
1444
|
# If an auth_config was already created via the button, use it and include initiation fields
|
|
@@ -1437,7 +1472,7 @@ class ComposioBaseComponent(Component):
|
|
|
1437
1472
|
# Clear action blocker text on successful initiation
|
|
1438
1473
|
build_config["action_button"]["helper_text"] = ""
|
|
1439
1474
|
build_config["action_button"]["helper_text_metadata"] = {}
|
|
1440
|
-
return build_config
|
|
1475
|
+
return self.update_input_types(build_config)
|
|
1441
1476
|
# Otherwise, create custom OAuth2 auth config using schema-declared required fields
|
|
1442
1477
|
credentials = {}
|
|
1443
1478
|
missing = []
|
|
@@ -1487,7 +1522,7 @@ class ComposioBaseComponent(Component):
|
|
|
1487
1522
|
build_config["auth_link"]["auth_config_id"] = auth_config_id
|
|
1488
1523
|
build_config["auth_link"]["value"] = "connect"
|
|
1489
1524
|
build_config["auth_link"]["auth_tooltip"] = "Connect"
|
|
1490
|
-
return build_config
|
|
1525
|
+
return self.update_input_types(build_config)
|
|
1491
1526
|
# Otherwise initiate immediately
|
|
1492
1527
|
redirect = composio.connected_accounts.initiate(
|
|
1493
1528
|
user_id=self.entity_id,
|
|
@@ -1504,7 +1539,7 @@ class ComposioBaseComponent(Component):
|
|
|
1504
1539
|
self._clear_auth_fields_from_schema(build_config, schema)
|
|
1505
1540
|
build_config["action_button"]["helper_text"] = ""
|
|
1506
1541
|
build_config["action_button"]["helper_text_metadata"] = {}
|
|
1507
|
-
return build_config
|
|
1542
|
+
return self.update_input_types(build_config)
|
|
1508
1543
|
if mode == "API_KEY":
|
|
1509
1544
|
ac = composio.auth_configs.create(
|
|
1510
1545
|
toolkit=toolkit_slug,
|
|
@@ -1550,7 +1585,7 @@ class ComposioBaseComponent(Component):
|
|
|
1550
1585
|
self._clear_auth_fields_from_schema(build_config, schema)
|
|
1551
1586
|
build_config["action_button"]["helper_text"] = ""
|
|
1552
1587
|
build_config["action_button"]["helper_text_metadata"] = {}
|
|
1553
|
-
return build_config
|
|
1588
|
+
return self.update_input_types(build_config)
|
|
1554
1589
|
# Generic custom auth flow for any other mode (treat like API_KEY)
|
|
1555
1590
|
ac = composio.auth_configs.create(
|
|
1556
1591
|
toolkit=toolkit_slug,
|
|
@@ -1584,13 +1619,13 @@ class ComposioBaseComponent(Component):
|
|
|
1584
1619
|
else:
|
|
1585
1620
|
build_config["auth_link"]["value"] = "validated"
|
|
1586
1621
|
build_config["auth_link"]["auth_tooltip"] = "Disconnect"
|
|
1587
|
-
return build_config
|
|
1622
|
+
return self.update_input_types(build_config)
|
|
1588
1623
|
except (ValueError, ConnectionError, TypeError) as e:
|
|
1589
1624
|
logger.error(f"Error creating connection: {e}")
|
|
1590
1625
|
build_config["auth_link"]["value"] = "connect"
|
|
1591
1626
|
build_config["auth_link"]["auth_tooltip"] = f"Error: {e!s}"
|
|
1592
1627
|
else:
|
|
1593
|
-
return build_config
|
|
1628
|
+
return self.update_input_types(build_config)
|
|
1594
1629
|
else:
|
|
1595
1630
|
# We already have a usable connection; no new OAuth request
|
|
1596
1631
|
build_config["auth_link"]["auth_tooltip"] = "Disconnect"
|
|
@@ -1732,7 +1767,7 @@ class ComposioBaseComponent(Component):
|
|
|
1732
1767
|
build_config["action_button"]["show"] = True # Show action field when tool mode is disabled
|
|
1733
1768
|
for field in self._all_fields:
|
|
1734
1769
|
build_config[field]["show"] = True # Update show status for all fields based on tool mode
|
|
1735
|
-
return build_config
|
|
1770
|
+
return self.update_input_types(build_config)
|
|
1736
1771
|
|
|
1737
1772
|
if field_name == "action_button":
|
|
1738
1773
|
# If selection is cancelled/cleared, remove generated fields
|
|
@@ -1748,12 +1783,12 @@ class ComposioBaseComponent(Component):
|
|
|
1748
1783
|
|
|
1749
1784
|
if _is_cleared(field_value):
|
|
1750
1785
|
self._hide_all_action_fields(build_config)
|
|
1751
|
-
return build_config
|
|
1786
|
+
return self.update_input_types(build_config)
|
|
1752
1787
|
|
|
1753
1788
|
self._update_action_config(build_config, field_value)
|
|
1754
1789
|
# Keep the existing show/hide behaviour
|
|
1755
1790
|
self.show_hide_fields(build_config, field_value)
|
|
1756
|
-
return build_config
|
|
1791
|
+
return self.update_input_types(build_config)
|
|
1757
1792
|
|
|
1758
1793
|
# Handle auth config button click
|
|
1759
1794
|
if field_name == "create_auth_config" and field_value == "create":
|
|
@@ -1798,7 +1833,7 @@ class ComposioBaseComponent(Component):
|
|
|
1798
1833
|
build_config["auth_link"]["auth_config_id"] = auth_config_id
|
|
1799
1834
|
build_config["auth_link"]["value"] = "connect"
|
|
1800
1835
|
build_config["auth_link"]["auth_tooltip"] = "Connect"
|
|
1801
|
-
return build_config
|
|
1836
|
+
return self.update_input_types(build_config)
|
|
1802
1837
|
# If no initiation fields required, initiate immediately
|
|
1803
1838
|
connection_request = composio.connected_accounts.initiate(
|
|
1804
1839
|
user_id=self.entity_id, auth_config_id=auth_config_id
|
|
@@ -1824,7 +1859,7 @@ class ComposioBaseComponent(Component):
|
|
|
1824
1859
|
logger.error(f"Error creating new auth config: {e}")
|
|
1825
1860
|
build_config["auth_link"]["value"] = "error"
|
|
1826
1861
|
build_config["auth_link"]["auth_tooltip"] = f"Error: {e!s}"
|
|
1827
|
-
return build_config
|
|
1862
|
+
return self.update_input_types(build_config)
|
|
1828
1863
|
|
|
1829
1864
|
# Handle API key removal
|
|
1830
1865
|
if field_name == "api_key" and len(field_value) == 0:
|
|
@@ -1861,16 +1896,16 @@ class ComposioBaseComponent(Component):
|
|
|
1861
1896
|
self._hide_all_action_fields(build_config)
|
|
1862
1897
|
except (TypeError, ValueError, AttributeError):
|
|
1863
1898
|
pass
|
|
1864
|
-
return build_config
|
|
1899
|
+
return self.update_input_types(build_config)
|
|
1865
1900
|
|
|
1866
1901
|
# Only proceed with connection logic if we have an API key
|
|
1867
1902
|
if not hasattr(self, "api_key") or not self.api_key:
|
|
1868
|
-
return build_config
|
|
1903
|
+
return self.update_input_types(build_config)
|
|
1869
1904
|
|
|
1870
1905
|
# CRITICAL: If tool_mode is enabled (check both instance and build_config), skip all connection logic
|
|
1871
1906
|
if current_tool_mode:
|
|
1872
1907
|
build_config["action_button"]["show"] = False
|
|
1873
|
-
return build_config
|
|
1908
|
+
return self.update_input_types(build_config)
|
|
1874
1909
|
|
|
1875
1910
|
# Update action options only if tool_mode is disabled
|
|
1876
1911
|
self._build_action_maps()
|
|
@@ -1931,7 +1966,7 @@ class ComposioBaseComponent(Component):
|
|
|
1931
1966
|
if self._is_tool_mode_enabled():
|
|
1932
1967
|
build_config["action_button"]["show"] = False
|
|
1933
1968
|
|
|
1934
|
-
return build_config
|
|
1969
|
+
return self.update_input_types(build_config)
|
|
1935
1970
|
|
|
1936
1971
|
def configure_tools(self, composio: Composio, limit: int | None = None) -> list[Tool]:
|
|
1937
1972
|
if limit is None:
|
|
@@ -2039,6 +2074,10 @@ class ComposioBaseComponent(Component):
|
|
|
2039
2074
|
final_field_name = field
|
|
2040
2075
|
if field.endswith("_user_id") and field.startswith(self.app_name):
|
|
2041
2076
|
final_field_name = "user_id"
|
|
2077
|
+
elif field == f"{self.app_name}_status":
|
|
2078
|
+
final_field_name = "status"
|
|
2079
|
+
elif field == f"{self.app_name}_name":
|
|
2080
|
+
final_field_name = "name"
|
|
2042
2081
|
|
|
2043
2082
|
arguments[final_field_name] = value
|
|
2044
2083
|
|
lfx/base/data/base_file.py
CHANGED
|
@@ -304,11 +304,12 @@ class BaseFileComponent(Component, ABC):
|
|
|
304
304
|
parts.append(str(data_text))
|
|
305
305
|
elif isinstance(d.data, dict):
|
|
306
306
|
# convert the data dict to a readable string
|
|
307
|
-
parts.append(orjson.dumps(d.data, default=str).decode())
|
|
307
|
+
parts.append(orjson.dumps(d.data, option=orjson.OPT_INDENT_2, default=str).decode())
|
|
308
308
|
else:
|
|
309
309
|
parts.append(str(d))
|
|
310
|
-
except
|
|
310
|
+
except Exception: # noqa: BLE001
|
|
311
311
|
# Final fallback - just try to convert to string
|
|
312
|
+
# TODO: Consider downstream error case more. Should this raise an error?
|
|
312
313
|
parts.append(str(d))
|
|
313
314
|
|
|
314
315
|
return Message(text=sep.join(parts), **metadata)
|
lfx/base/tools/flow_tool.py
CHANGED
|
@@ -6,7 +6,7 @@ from langchain_core.tools import BaseTool, ToolException
|
|
|
6
6
|
from typing_extensions import override
|
|
7
7
|
|
|
8
8
|
from lfx.base.flow_processing.utils import build_data_from_result_data, format_flow_output_data
|
|
9
|
-
from lfx.helpers
|
|
9
|
+
from lfx.helpers import build_schema_from_inputs, get_arg_names, get_flow_inputs, run_flow
|
|
10
10
|
from lfx.log.logger import logger
|
|
11
11
|
from lfx.utils.async_helpers import run_until_complete
|
|
12
12
|
|
lfx/base/tools/run_flow.py
CHANGED
|
@@ -5,7 +5,7 @@ from lfx.custom.custom_component.component import Component, get_component_toolk
|
|
|
5
5
|
from lfx.field_typing import Tool
|
|
6
6
|
from lfx.graph.graph.base import Graph
|
|
7
7
|
from lfx.graph.vertex.base import Vertex
|
|
8
|
-
from lfx.helpers
|
|
8
|
+
from lfx.helpers import get_flow_inputs
|
|
9
9
|
from lfx.inputs.inputs import DropdownInput, InputTypes, MessageInput
|
|
10
10
|
from lfx.log.logger import logger
|
|
11
11
|
from lfx.schema.data import Data
|
lfx/cli/commands.py
CHANGED
|
@@ -85,6 +85,11 @@ def serve_command(
|
|
|
85
85
|
cat my_flow.json | lfx serve --stdin
|
|
86
86
|
echo '{"nodes": [...]}' | lfx serve --stdin
|
|
87
87
|
"""
|
|
88
|
+
# Configure logging with the specified level and import logger
|
|
89
|
+
from lfx.log.logger import configure, logger
|
|
90
|
+
|
|
91
|
+
configure(log_level=log_level)
|
|
92
|
+
|
|
88
93
|
verbose_print = create_verbose_printer(verbose=verbose)
|
|
89
94
|
|
|
90
95
|
# Validate input sources - exactly one must be provided
|
|
@@ -134,11 +139,11 @@ def serve_command(
|
|
|
134
139
|
temp_file_to_cleanup = None
|
|
135
140
|
|
|
136
141
|
if flow_json is not None:
|
|
137
|
-
|
|
142
|
+
logger.info("Processing inline JSON content...")
|
|
138
143
|
try:
|
|
139
144
|
# Validate JSON syntax
|
|
140
145
|
json_data = json.loads(flow_json)
|
|
141
|
-
|
|
146
|
+
logger.info("JSON content is valid")
|
|
142
147
|
|
|
143
148
|
# Create a temporary file with the JSON content
|
|
144
149
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as temp_file:
|
|
@@ -146,7 +151,7 @@ def serve_command(
|
|
|
146
151
|
temp_file_to_cleanup = temp_file.name
|
|
147
152
|
|
|
148
153
|
script_path = temp_file_to_cleanup
|
|
149
|
-
|
|
154
|
+
logger.info(f"Created temporary file: {script_path}")
|
|
150
155
|
|
|
151
156
|
except json.JSONDecodeError as e:
|
|
152
157
|
typer.echo(f"Error: Invalid JSON content: {e}", err=True)
|
|
@@ -156,17 +161,17 @@ def serve_command(
|
|
|
156
161
|
raise typer.Exit(1) from e
|
|
157
162
|
|
|
158
163
|
elif stdin:
|
|
159
|
-
|
|
164
|
+
logger.info("Reading JSON content from stdin...")
|
|
160
165
|
try:
|
|
161
166
|
# Read all content from stdin
|
|
162
167
|
stdin_content = sys.stdin.read().strip()
|
|
163
168
|
if not stdin_content:
|
|
164
|
-
|
|
169
|
+
logger.error("No content received from stdin")
|
|
165
170
|
raise typer.Exit(1)
|
|
166
171
|
|
|
167
172
|
# Validate JSON syntax
|
|
168
173
|
json_data = json.loads(stdin_content)
|
|
169
|
-
|
|
174
|
+
logger.info("JSON content from stdin is valid")
|
|
170
175
|
|
|
171
176
|
# Create a temporary file with the JSON content
|
|
172
177
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as temp_file:
|
|
@@ -174,7 +179,7 @@ def serve_command(
|
|
|
174
179
|
temp_file_to_cleanup = temp_file.name
|
|
175
180
|
|
|
176
181
|
script_path = temp_file_to_cleanup
|
|
177
|
-
|
|
182
|
+
logger.info(f"Created temporary file from stdin: {script_path}")
|
|
178
183
|
|
|
179
184
|
except json.JSONDecodeError as e:
|
|
180
185
|
verbose_print(f"Error: Invalid JSON content from stdin: {e}")
|
|
@@ -210,10 +215,10 @@ def serve_command(
|
|
|
210
215
|
raise typer.Exit(1)
|
|
211
216
|
|
|
212
217
|
# Prepare the graph
|
|
213
|
-
|
|
218
|
+
logger.info("Preparing graph for serving...")
|
|
214
219
|
try:
|
|
215
220
|
graph.prepare()
|
|
216
|
-
|
|
221
|
+
logger.info("Graph prepared successfully")
|
|
217
222
|
|
|
218
223
|
# Validate global variables for environment compatibility
|
|
219
224
|
if check_variables:
|
|
@@ -221,12 +226,12 @@ def serve_command(
|
|
|
221
226
|
|
|
222
227
|
validation_errors = validate_global_variables_for_env(graph)
|
|
223
228
|
if validation_errors:
|
|
224
|
-
|
|
229
|
+
logger.error("Global variable validation failed:")
|
|
225
230
|
for error in validation_errors:
|
|
226
|
-
|
|
231
|
+
logger.error(f" - {error}")
|
|
227
232
|
raise typer.Exit(1)
|
|
228
233
|
else:
|
|
229
|
-
|
|
234
|
+
logger.info("Global variable validation skipped")
|
|
230
235
|
except Exception as e:
|
|
231
236
|
verbose_print(f"✗ Failed to prepare graph: {e}")
|
|
232
237
|
raise typer.Exit(1) from e
|