griptape-nodes 0.58.1__py3-none-any.whl → 0.59.1__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.
- griptape_nodes/bootstrap/utils/python_subprocess_executor.py +2 -2
- griptape_nodes/bootstrap/workflow_executors/local_session_workflow_executor.py +0 -5
- griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +9 -5
- griptape_nodes/bootstrap/workflow_executors/subprocess_workflow_executor.py +0 -1
- griptape_nodes/bootstrap/workflow_executors/workflow_executor.py +1 -3
- griptape_nodes/bootstrap/workflow_publishers/local_workflow_publisher.py +1 -1
- griptape_nodes/cli/commands/init.py +53 -7
- griptape_nodes/cli/shared.py +1 -0
- griptape_nodes/common/node_executor.py +218 -42
- griptape_nodes/exe_types/core_types.py +46 -0
- griptape_nodes/exe_types/node_types.py +272 -0
- griptape_nodes/machines/control_flow.py +222 -16
- griptape_nodes/machines/dag_builder.py +212 -1
- griptape_nodes/machines/parallel_resolution.py +237 -4
- griptape_nodes/node_library/workflow_registry.py +1 -1
- griptape_nodes/retained_mode/events/execution_events.py +5 -4
- griptape_nodes/retained_mode/events/flow_events.py +17 -67
- griptape_nodes/retained_mode/events/parameter_events.py +122 -1
- griptape_nodes/retained_mode/managers/event_manager.py +17 -13
- griptape_nodes/retained_mode/managers/flow_manager.py +316 -573
- griptape_nodes/retained_mode/managers/library_manager.py +32 -20
- griptape_nodes/retained_mode/managers/model_manager.py +19 -8
- griptape_nodes/retained_mode/managers/node_manager.py +463 -3
- griptape_nodes/retained_mode/managers/object_manager.py +2 -2
- griptape_nodes/retained_mode/managers/workflow_manager.py +37 -46
- griptape_nodes/retained_mode/retained_mode.py +297 -3
- {griptape_nodes-0.58.1.dist-info → griptape_nodes-0.59.1.dist-info}/METADATA +3 -2
- {griptape_nodes-0.58.1.dist-info → griptape_nodes-0.59.1.dist-info}/RECORD +30 -30
- {griptape_nodes-0.58.1.dist-info → griptape_nodes-0.59.1.dist-info}/WHEEL +1 -1
- {griptape_nodes-0.58.1.dist-info → griptape_nodes-0.59.1.dist-info}/entry_points.txt +0 -0
|
@@ -21,6 +21,7 @@ from griptape_nodes.exe_types.node_types import (
|
|
|
21
21
|
BaseNode,
|
|
22
22
|
ErrorProxyNode,
|
|
23
23
|
NodeDependencies,
|
|
24
|
+
NodeGroupProxyNode,
|
|
24
25
|
NodeResolutionState,
|
|
25
26
|
StartLoopNode,
|
|
26
27
|
StartNode,
|
|
@@ -106,9 +107,6 @@ from griptape_nodes.retained_mode.events.flow_events import (
|
|
|
106
107
|
ListNodesInFlowResultFailure,
|
|
107
108
|
ListNodesInFlowResultSuccess,
|
|
108
109
|
OriginalNodeParameter,
|
|
109
|
-
PackageNodeAsSerializedFlowRequest,
|
|
110
|
-
PackageNodeAsSerializedFlowResultFailure,
|
|
111
|
-
PackageNodeAsSerializedFlowResultSuccess,
|
|
112
110
|
PackageNodesAsSerializedFlowRequest,
|
|
113
111
|
PackageNodesAsSerializedFlowResultFailure,
|
|
114
112
|
PackageNodesAsSerializedFlowResultSuccess,
|
|
@@ -262,9 +260,6 @@ class FlowManager:
|
|
|
262
260
|
event_manager.assign_manager_to_request_type(
|
|
263
261
|
DeserializeFlowFromCommandsRequest, self.on_deserialize_flow_from_commands
|
|
264
262
|
)
|
|
265
|
-
event_manager.assign_manager_to_request_type(
|
|
266
|
-
PackageNodeAsSerializedFlowRequest, self.on_package_node_as_serialized_flow_request
|
|
267
|
-
)
|
|
268
263
|
event_manager.assign_manager_to_request_type(
|
|
269
264
|
PackageNodesAsSerializedFlowRequest, self.on_package_nodes_as_serialized_flow_request
|
|
270
265
|
)
|
|
@@ -937,11 +932,15 @@ class FlowManager:
|
|
|
937
932
|
if isinstance(target_param, ParameterContainer):
|
|
938
933
|
target_node.kill_parameter_children(target_param)
|
|
939
934
|
# Set the parameter value (including None/empty values) unless we're in initial setup
|
|
940
|
-
# Skip propagation for
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
935
|
+
# Skip propagation for:
|
|
936
|
+
# 1. Control Parameters as they should not receive values
|
|
937
|
+
# 2. Locked nodes
|
|
938
|
+
# 3. Initial Setup (this is used during deserialization; the downstream node may not be created yet)
|
|
939
|
+
is_control_parameter = (
|
|
940
|
+
ParameterType.attempt_get_builtin(source_param.output_type) == ParameterTypeBuiltin.CONTROL_TYPE
|
|
941
|
+
)
|
|
942
|
+
is_dest_node_locked = target_node.lock
|
|
943
|
+
if (not is_control_parameter) and (not is_dest_node_locked) and (not request.initial_setup):
|
|
945
944
|
# When creating a connection, pass the initial value from source to target parameter
|
|
946
945
|
# Set incoming_connection_source fields to identify this as legitimate connection value passing
|
|
947
946
|
# (not manual property setting) so it bypasses the INPUT+PROPERTY connection blocking logic
|
|
@@ -1104,521 +1103,7 @@ class FlowManager:
|
|
|
1104
1103
|
result = DeleteConnectionResultSuccess(result_details=details)
|
|
1105
1104
|
return result
|
|
1106
1105
|
|
|
1107
|
-
def
|
|
1108
|
-
"""Handle request to package a node as a serialized flow.
|
|
1109
|
-
|
|
1110
|
-
Creates a self-contained flow with Start node -> Package node -> End node structure,
|
|
1111
|
-
where artificial start/end nodes match the package node's connections.
|
|
1112
|
-
"""
|
|
1113
|
-
# Step 1: Validate package node and flow
|
|
1114
|
-
package_node_info = self._validate_package_node_and_flow(request=request)
|
|
1115
|
-
if isinstance(package_node_info, PackageNodeAsSerializedFlowResultFailure):
|
|
1116
|
-
return package_node_info
|
|
1117
|
-
|
|
1118
|
-
# Step 2: Validate library and get version
|
|
1119
|
-
library_version = self._validate_and_get_library_info(request=request)
|
|
1120
|
-
if isinstance(library_version, PackageNodeAsSerializedFlowResultFailure):
|
|
1121
|
-
return library_version
|
|
1122
|
-
|
|
1123
|
-
# Step 3: Analyze package node connections
|
|
1124
|
-
connection_analysis = self._analyze_package_node_connections(
|
|
1125
|
-
package_node=package_node_info.package_node,
|
|
1126
|
-
node_name=package_node_info.package_node.name,
|
|
1127
|
-
)
|
|
1128
|
-
if isinstance(connection_analysis, PackageNodeAsSerializedFlowResultFailure):
|
|
1129
|
-
return connection_analysis
|
|
1130
|
-
|
|
1131
|
-
# Step 4: Serialize the package node
|
|
1132
|
-
unique_parameter_uuid_to_values = {}
|
|
1133
|
-
serialized_parameter_value_tracker = SerializedParameterValueTracker()
|
|
1134
|
-
package_node = package_node_info.package_node
|
|
1135
|
-
# Set to LOCAL_EXECUTION before packaging to prevent recursive loop.
|
|
1136
|
-
previous_value = package_node.get_parameter_value("execution_environment")
|
|
1137
|
-
package_node.set_parameter_value("execution_environment", LOCAL_EXECUTION)
|
|
1138
|
-
serialized_package_result = self._serialize_package_node(
|
|
1139
|
-
node_name=package_node_info.package_node.name,
|
|
1140
|
-
package_node=package_node_info.package_node,
|
|
1141
|
-
unique_parameter_uuid_to_values=unique_parameter_uuid_to_values,
|
|
1142
|
-
serialized_parameter_value_tracker=serialized_parameter_value_tracker,
|
|
1143
|
-
)
|
|
1144
|
-
# Now that we've serialized the value as LOCAL_EXECUTION, we need to restore it to whatever it was before
|
|
1145
|
-
package_node.set_parameter_value("execution_environment", previous_value)
|
|
1146
|
-
if isinstance(serialized_package_result, PackageNodeAsSerializedFlowResultFailure):
|
|
1147
|
-
return serialized_package_result
|
|
1148
|
-
# Step 5: Create start node commands and data connections
|
|
1149
|
-
start_node_result = self._create_start_node_commands(
|
|
1150
|
-
request=request,
|
|
1151
|
-
incoming_data_connections=connection_analysis.incoming_data_connections,
|
|
1152
|
-
package_node=package_node_info.package_node,
|
|
1153
|
-
package_node_uuid=serialized_package_result.serialized_node_commands.node_uuid,
|
|
1154
|
-
library_version=library_version,
|
|
1155
|
-
unique_parameter_uuid_to_values=unique_parameter_uuid_to_values,
|
|
1156
|
-
serialized_parameter_value_tracker=serialized_parameter_value_tracker,
|
|
1157
|
-
)
|
|
1158
|
-
if isinstance(start_node_result, PackageNodeAsSerializedFlowResultFailure):
|
|
1159
|
-
return start_node_result
|
|
1160
|
-
|
|
1161
|
-
# Step 6: Create end node commands and data connections
|
|
1162
|
-
end_node_result = self._create_end_node_commands(
|
|
1163
|
-
request=request,
|
|
1164
|
-
package_node=package_node_info.package_node,
|
|
1165
|
-
package_node_uuid=serialized_package_result.serialized_node_commands.node_uuid,
|
|
1166
|
-
library_version=library_version,
|
|
1167
|
-
)
|
|
1168
|
-
if isinstance(end_node_result, PackageNodeAsSerializedFlowResultFailure):
|
|
1169
|
-
return end_node_result
|
|
1170
|
-
|
|
1171
|
-
# Step 7a: Create start node control flow connection
|
|
1172
|
-
start_control_connection_result = self._create_start_node_control_connection(
|
|
1173
|
-
entry_control_parameter_name=request.entry_control_parameter_name,
|
|
1174
|
-
start_node_uuid=start_node_result.start_node_commands.node_uuid,
|
|
1175
|
-
package_node_uuid=serialized_package_result.serialized_node_commands.node_uuid,
|
|
1176
|
-
package_node=package_node_info.package_node,
|
|
1177
|
-
)
|
|
1178
|
-
if isinstance(start_control_connection_result, PackageNodeAsSerializedFlowResultFailure):
|
|
1179
|
-
return start_control_connection_result
|
|
1180
|
-
|
|
1181
|
-
start_control_connections = [start_control_connection_result]
|
|
1182
|
-
|
|
1183
|
-
# Use only start control connections for now (end node control connections not implemented yet)
|
|
1184
|
-
control_flow_connections = start_control_connections
|
|
1185
|
-
|
|
1186
|
-
# Step 8: Assemble the complete serialized flow
|
|
1187
|
-
packaged_flow = self._assemble_serialized_flow(
|
|
1188
|
-
serialized_package_result=serialized_package_result,
|
|
1189
|
-
start_node_result=start_node_result,
|
|
1190
|
-
end_node_result=end_node_result,
|
|
1191
|
-
control_flow_connections=control_flow_connections,
|
|
1192
|
-
unique_parameter_uuid_to_values=unique_parameter_uuid_to_values,
|
|
1193
|
-
library_version=library_version,
|
|
1194
|
-
request=request,
|
|
1195
|
-
)
|
|
1196
|
-
|
|
1197
|
-
# Step 9: Build WorkflowShape from collected parameter shape data
|
|
1198
|
-
workflow_shape = GriptapeNodes.WorkflowManager().build_workflow_shape_from_parameter_info(
|
|
1199
|
-
input_node_params=start_node_result.input_shape_data, output_node_params=end_node_result.output_shape_data
|
|
1200
|
-
)
|
|
1201
|
-
# Return success result
|
|
1202
|
-
return PackageNodeAsSerializedFlowResultSuccess(
|
|
1203
|
-
result_details=f'Successfully packaged node "{package_node_info.package_node.name}" from flow "{package_node_info.package_flow_name}" as serialized flow with start node type "{request.start_node_type}" and end node type "{request.end_node_type}" from library "{request.start_end_specific_library_name}".',
|
|
1204
|
-
serialized_flow_commands=packaged_flow,
|
|
1205
|
-
workflow_shape=workflow_shape,
|
|
1206
|
-
)
|
|
1207
|
-
|
|
1208
|
-
def _validate_package_node_and_flow( # noqa: PLR0911
|
|
1209
|
-
self, request: PackageNodeAsSerializedFlowRequest
|
|
1210
|
-
) -> PackageNodeInfo | PackageNodeAsSerializedFlowResultFailure:
|
|
1211
|
-
"""Validate and retrieve the package node and its parent flow."""
|
|
1212
|
-
node_name = request.node_name
|
|
1213
|
-
package_node = None
|
|
1214
|
-
|
|
1215
|
-
if node_name is None:
|
|
1216
|
-
# First check if we have a current node
|
|
1217
|
-
if not GriptapeNodes.ContextManager().has_current_node():
|
|
1218
|
-
details = (
|
|
1219
|
-
"Attempted to package node from Current Context. Failed because the Current Context was empty."
|
|
1220
|
-
)
|
|
1221
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1222
|
-
|
|
1223
|
-
# Get the current node from context
|
|
1224
|
-
package_node = GriptapeNodes.ContextManager().get_current_node()
|
|
1225
|
-
node_name = package_node.name
|
|
1226
|
-
|
|
1227
|
-
if package_node is None:
|
|
1228
|
-
try:
|
|
1229
|
-
package_node = GriptapeNodes.NodeManager().get_node_by_name(node_name)
|
|
1230
|
-
except ValueError as err:
|
|
1231
|
-
details = f"Attempted to package node '{node_name}'. Failed because node does not exist. Error: {err}."
|
|
1232
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1233
|
-
|
|
1234
|
-
# Get the flow containing this node using the same pattern
|
|
1235
|
-
package_flow_name = GriptapeNodes.NodeManager().get_node_parent_flow_by_name(node_name)
|
|
1236
|
-
if package_flow_name is None:
|
|
1237
|
-
details = f"Attempted to package node '{node_name}'. Failed because node is not assigned to any flow."
|
|
1238
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1239
|
-
|
|
1240
|
-
try:
|
|
1241
|
-
self.get_flow_by_name(flow_name=package_flow_name)
|
|
1242
|
-
except KeyError as err:
|
|
1243
|
-
details = f"Attempted to package node '{node_name}' from flow '{package_flow_name}'. Failed because flow does not exist. Error: {err}."
|
|
1244
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1245
|
-
|
|
1246
|
-
# Validate entry control parameter if specified
|
|
1247
|
-
if request.entry_control_parameter_name is not None:
|
|
1248
|
-
entry_param = package_node.get_parameter_by_name(request.entry_control_parameter_name)
|
|
1249
|
-
if entry_param is None:
|
|
1250
|
-
details = f"Attempted to package node '{node_name}' with entry control parameter '{request.entry_control_parameter_name}'. Failed because the parameter does not exist on the node."
|
|
1251
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1252
|
-
|
|
1253
|
-
# Verify it's actually a control parameter
|
|
1254
|
-
if ParameterTypeBuiltin.CONTROL_TYPE.value not in entry_param.input_types:
|
|
1255
|
-
details = f"Attempted to package node '{node_name}' with entry control parameter '{request.entry_control_parameter_name}'. Failed because the parameter is not a control type parameter."
|
|
1256
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1257
|
-
|
|
1258
|
-
return PackageNodeInfo(package_node=package_node, package_flow_name=package_flow_name)
|
|
1259
|
-
|
|
1260
|
-
def _validate_and_get_library_info(
|
|
1261
|
-
self, request: PackageNodeAsSerializedFlowRequest
|
|
1262
|
-
) -> str | PackageNodeAsSerializedFlowResultFailure:
|
|
1263
|
-
"""Validate start/end node types exist in library and return library version."""
|
|
1264
|
-
# Early validation - ensure both start and end node types exist in the specified library
|
|
1265
|
-
try:
|
|
1266
|
-
start_end_library = LibraryRegistry.get_library_for_node_type(
|
|
1267
|
-
node_type=request.start_node_type, specific_library_name=request.start_end_specific_library_name
|
|
1268
|
-
)
|
|
1269
|
-
except KeyError as err:
|
|
1270
|
-
details = f"Attempted to package node with start node type '{request.start_node_type}' from library '{request.start_end_specific_library_name}'. Failed because start node type was not found in library. Error: {err}."
|
|
1271
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1272
|
-
|
|
1273
|
-
try:
|
|
1274
|
-
LibraryRegistry.get_library_for_node_type(
|
|
1275
|
-
node_type=request.end_node_type, specific_library_name=request.start_end_specific_library_name
|
|
1276
|
-
)
|
|
1277
|
-
except KeyError as err:
|
|
1278
|
-
details = f"Attempted to package node with end node type '{request.end_node_type}' from library '{request.start_end_specific_library_name}'. Failed because end node type was not found in library. Error: {err}."
|
|
1279
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1280
|
-
|
|
1281
|
-
# Get the actual library version
|
|
1282
|
-
start_end_library_metadata = start_end_library.get_metadata()
|
|
1283
|
-
return start_end_library_metadata.library_version
|
|
1284
|
-
|
|
1285
|
-
def _serialize_package_node(
|
|
1286
|
-
self,
|
|
1287
|
-
node_name: str,
|
|
1288
|
-
package_node: BaseNode,
|
|
1289
|
-
unique_parameter_uuid_to_values: dict[SerializedNodeCommands.UniqueParameterValueUUID, Any],
|
|
1290
|
-
serialized_parameter_value_tracker: SerializedParameterValueTracker,
|
|
1291
|
-
) -> SerializeNodeToCommandsResultSuccess | PackageNodeAsSerializedFlowResultFailure:
|
|
1292
|
-
"""Serialize the package node to commands, adding OUTPUT mode to PROPERTY-only parameters."""
|
|
1293
|
-
# Use the provided parameter tracking structures
|
|
1294
|
-
|
|
1295
|
-
# Create serialization request for the package node
|
|
1296
|
-
serialize_node_request = SerializeNodeToCommandsRequest(
|
|
1297
|
-
node_name=node_name,
|
|
1298
|
-
unique_parameter_uuid_to_values=unique_parameter_uuid_to_values,
|
|
1299
|
-
serialized_parameter_value_tracker=serialized_parameter_value_tracker,
|
|
1300
|
-
)
|
|
1301
|
-
|
|
1302
|
-
# Execute the serialization
|
|
1303
|
-
serialize_node_result = GriptapeNodes.handle_request(serialize_node_request)
|
|
1304
|
-
if not isinstance(serialize_node_result, SerializeNodeToCommandsResultSuccess):
|
|
1305
|
-
details = f"Attempted to serialize package node '{node_name}'. Failed because node serialization failed."
|
|
1306
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1307
|
-
|
|
1308
|
-
# Add ALTER parameter commands for PROPERTY-only parameters to enable OUTPUT mode
|
|
1309
|
-
# We need these to emit their values back so that the orchestrator/caller
|
|
1310
|
-
# can reconcile the packaged node's values after it is executed.
|
|
1311
|
-
package_alter_parameter_commands = []
|
|
1312
|
-
for package_param in package_node.parameters:
|
|
1313
|
-
has_output_mode = ParameterMode.OUTPUT in package_param.allowed_modes
|
|
1314
|
-
has_property_mode = ParameterMode.PROPERTY in package_param.allowed_modes
|
|
1315
|
-
|
|
1316
|
-
# If has PROPERTY but not OUTPUT, add ALTER command to enable OUTPUT
|
|
1317
|
-
if has_property_mode and not has_output_mode:
|
|
1318
|
-
alter_param_request = AlterParameterDetailsRequest(
|
|
1319
|
-
parameter_name=package_param.name,
|
|
1320
|
-
node_name=package_node.name,
|
|
1321
|
-
mode_allowed_output=True,
|
|
1322
|
-
)
|
|
1323
|
-
package_alter_parameter_commands.append(alter_param_request)
|
|
1324
|
-
|
|
1325
|
-
# If we have alter parameter commands, append them to the existing element_modification_commands
|
|
1326
|
-
if package_alter_parameter_commands:
|
|
1327
|
-
serialize_node_result.serialized_node_commands.element_modification_commands.extend(
|
|
1328
|
-
package_alter_parameter_commands
|
|
1329
|
-
)
|
|
1330
|
-
|
|
1331
|
-
return serialize_node_result
|
|
1332
|
-
|
|
1333
|
-
def _create_start_node_commands( # noqa: PLR0913
|
|
1334
|
-
self,
|
|
1335
|
-
request: PackageNodeAsSerializedFlowRequest,
|
|
1336
|
-
incoming_data_connections: list[IncomingConnection],
|
|
1337
|
-
package_node: BaseNode,
|
|
1338
|
-
package_node_uuid: SerializedNodeCommands.NodeUUID,
|
|
1339
|
-
library_version: str,
|
|
1340
|
-
unique_parameter_uuid_to_values: dict[SerializedNodeCommands.UniqueParameterValueUUID, Any],
|
|
1341
|
-
serialized_parameter_value_tracker: SerializedParameterValueTracker,
|
|
1342
|
-
) -> PackagingStartNodeResult | PackageNodeAsSerializedFlowResultFailure:
|
|
1343
|
-
"""Create start node commands and connections for incoming data connections."""
|
|
1344
|
-
# Generate UUID and name for start node
|
|
1345
|
-
start_node_uuid = SerializedNodeCommands.NodeUUID(str(uuid4()))
|
|
1346
|
-
start_node_name = f"Start_Package_{package_node.name}"
|
|
1347
|
-
|
|
1348
|
-
# Build start node CreateNodeRequest
|
|
1349
|
-
start_create_node_command = CreateNodeRequest(
|
|
1350
|
-
node_type=request.start_node_type,
|
|
1351
|
-
specific_library_name=request.start_end_specific_library_name,
|
|
1352
|
-
node_name=start_node_name,
|
|
1353
|
-
metadata={},
|
|
1354
|
-
initial_setup=True,
|
|
1355
|
-
create_error_proxy_on_failure=False,
|
|
1356
|
-
)
|
|
1357
|
-
|
|
1358
|
-
# Create library details
|
|
1359
|
-
start_node_library_details = LibraryNameAndVersion(
|
|
1360
|
-
library_name=request.start_end_specific_library_name,
|
|
1361
|
-
library_version=library_version,
|
|
1362
|
-
)
|
|
1363
|
-
|
|
1364
|
-
# Create parameter modification commands and connection mappings for the start node based on incoming DATA connections
|
|
1365
|
-
start_node_parameter_commands = []
|
|
1366
|
-
start_to_package_connections = []
|
|
1367
|
-
start_node_parameter_value_commands = []
|
|
1368
|
-
input_shape_data: WorkflowShapeNodes = {}
|
|
1369
|
-
|
|
1370
|
-
for incoming_conn in incoming_data_connections:
|
|
1371
|
-
# Parameter name: use the package node's parameter name
|
|
1372
|
-
param_name = incoming_conn.target_parameter_name
|
|
1373
|
-
|
|
1374
|
-
# Get the source node to determine parameter type
|
|
1375
|
-
try:
|
|
1376
|
-
source_node = GriptapeNodes.NodeManager().get_node_by_name(incoming_conn.source_node_name)
|
|
1377
|
-
except ValueError as err:
|
|
1378
|
-
details = f"Attempted to package node '{package_node.name}'. Failed because source node '{incoming_conn.source_node_name}' from incoming connection could not be found. Error: {err}."
|
|
1379
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1380
|
-
|
|
1381
|
-
# Get the source parameter
|
|
1382
|
-
source_param = source_node.get_parameter_by_name(incoming_conn.source_parameter_name)
|
|
1383
|
-
if not source_param:
|
|
1384
|
-
details = f"Attempted to package node '{package_node.name}'. Failed because source parameter '{incoming_conn.source_parameter_name}' on node '{incoming_conn.source_node_name}' from incoming connection could not be found."
|
|
1385
|
-
return PackageNodeAsSerializedFlowResultFailure(result_details=details)
|
|
1386
|
-
|
|
1387
|
-
# Extract parameter shape info for workflow shape (inputs from external sources)
|
|
1388
|
-
param_shape_info = GriptapeNodes.WorkflowManager().extract_parameter_shape_info(
|
|
1389
|
-
source_param, include_control_params=True
|
|
1390
|
-
)
|
|
1391
|
-
if param_shape_info is not None:
|
|
1392
|
-
if start_node_name not in input_shape_data:
|
|
1393
|
-
input_shape_data[start_node_name] = {}
|
|
1394
|
-
input_shape_data[start_node_name][param_name] = param_shape_info
|
|
1395
|
-
|
|
1396
|
-
# Extract parameter value from source node to set on start node
|
|
1397
|
-
param_value_commands = GriptapeNodes.NodeManager().handle_parameter_value_saving(
|
|
1398
|
-
parameter=source_param,
|
|
1399
|
-
node=source_node,
|
|
1400
|
-
unique_parameter_uuid_to_values=unique_parameter_uuid_to_values,
|
|
1401
|
-
serialized_parameter_value_tracker=serialized_parameter_value_tracker,
|
|
1402
|
-
create_node_request=start_create_node_command,
|
|
1403
|
-
)
|
|
1404
|
-
if param_value_commands is not None:
|
|
1405
|
-
# Modify each command to target the start node parameter instead
|
|
1406
|
-
for param_value_command in param_value_commands:
|
|
1407
|
-
param_value_command.set_parameter_value_command.node_name = start_node_name
|
|
1408
|
-
param_value_command.set_parameter_value_command.parameter_name = param_name
|
|
1409
|
-
start_node_parameter_value_commands.append(param_value_command)
|
|
1410
|
-
|
|
1411
|
-
# Create parameter command for start node
|
|
1412
|
-
add_param_request = AddParameterToNodeRequest(
|
|
1413
|
-
node_name=start_node_name,
|
|
1414
|
-
parameter_name=param_name,
|
|
1415
|
-
# Use the source parameter's output_type as the type for our start node parameter
|
|
1416
|
-
# since we want to match what the original connection was providing
|
|
1417
|
-
type=source_param.output_type,
|
|
1418
|
-
default_value=None,
|
|
1419
|
-
tooltip=f"Parameter {param_name} from packaged flow",
|
|
1420
|
-
initial_setup=True,
|
|
1421
|
-
)
|
|
1422
|
-
start_node_parameter_commands.append(add_param_request)
|
|
1423
|
-
|
|
1424
|
-
# Create connection from start node to package node
|
|
1425
|
-
start_to_package_connection = SerializedFlowCommands.IndirectConnectionSerialization(
|
|
1426
|
-
source_node_uuid=start_node_uuid,
|
|
1427
|
-
source_parameter_name=param_name,
|
|
1428
|
-
target_node_uuid=package_node_uuid,
|
|
1429
|
-
target_parameter_name=param_name,
|
|
1430
|
-
)
|
|
1431
|
-
start_to_package_connections.append(start_to_package_connection)
|
|
1432
|
-
|
|
1433
|
-
# Build complete SerializedNodeCommands for start node
|
|
1434
|
-
start_node_dependencies = NodeDependencies()
|
|
1435
|
-
start_node_dependencies.libraries.add(start_node_library_details)
|
|
1436
|
-
|
|
1437
|
-
start_node_commands = SerializedNodeCommands(
|
|
1438
|
-
create_node_command=start_create_node_command,
|
|
1439
|
-
element_modification_commands=start_node_parameter_commands,
|
|
1440
|
-
node_dependencies=start_node_dependencies,
|
|
1441
|
-
node_uuid=start_node_uuid,
|
|
1442
|
-
)
|
|
1443
|
-
|
|
1444
|
-
return PackagingStartNodeResult(
|
|
1445
|
-
start_node_commands=start_node_commands,
|
|
1446
|
-
start_to_package_connections=start_to_package_connections,
|
|
1447
|
-
input_shape_data=input_shape_data,
|
|
1448
|
-
start_node_parameter_value_commands=start_node_parameter_value_commands,
|
|
1449
|
-
)
|
|
1450
|
-
|
|
1451
|
-
def _create_end_node_commands(
|
|
1452
|
-
self,
|
|
1453
|
-
request: PackageNodeAsSerializedFlowRequest,
|
|
1454
|
-
package_node: BaseNode,
|
|
1455
|
-
package_node_uuid: SerializedNodeCommands.NodeUUID,
|
|
1456
|
-
library_version: str,
|
|
1457
|
-
) -> PackagingEndNodeResult | PackageNodeAsSerializedFlowResultFailure:
|
|
1458
|
-
"""Create end node commands and connections for ALL package parameters that meet criteria."""
|
|
1459
|
-
# Generate UUID and name for end node
|
|
1460
|
-
end_node_uuid = SerializedNodeCommands.NodeUUID(str(uuid4()))
|
|
1461
|
-
end_node_name = f"End_Package_{package_node.name}"
|
|
1462
|
-
|
|
1463
|
-
# Build end node CreateNodeRequest
|
|
1464
|
-
end_create_node_command = CreateNodeRequest(
|
|
1465
|
-
node_type=request.end_node_type,
|
|
1466
|
-
specific_library_name=request.start_end_specific_library_name,
|
|
1467
|
-
node_name=end_node_name,
|
|
1468
|
-
metadata={},
|
|
1469
|
-
initial_setup=True,
|
|
1470
|
-
create_error_proxy_on_failure=False,
|
|
1471
|
-
)
|
|
1472
|
-
|
|
1473
|
-
# Create library details
|
|
1474
|
-
end_node_library_details = LibraryNameAndVersion(
|
|
1475
|
-
library_name=request.start_end_specific_library_name,
|
|
1476
|
-
library_version=library_version,
|
|
1477
|
-
)
|
|
1478
|
-
|
|
1479
|
-
# Process ALL package node parameters to create end node parameters and connections
|
|
1480
|
-
# Note: PROPERTY-only parameters are guaranteed to have OUTPUT mode after serialization
|
|
1481
|
-
end_node_parameter_commands = []
|
|
1482
|
-
package_to_end_connections = []
|
|
1483
|
-
output_shape_data: WorkflowShapeNodes = {}
|
|
1484
|
-
|
|
1485
|
-
for package_param in package_node.parameters:
|
|
1486
|
-
# Only ignore parameters that have ONLY INPUT mode (no OUTPUT or PROPERTY)
|
|
1487
|
-
has_output_mode = ParameterMode.OUTPUT in package_param.allowed_modes
|
|
1488
|
-
has_property_mode = ParameterMode.PROPERTY in package_param.allowed_modes
|
|
1489
|
-
|
|
1490
|
-
# Skip parameters that only have INPUT mode
|
|
1491
|
-
if not has_output_mode and not has_property_mode:
|
|
1492
|
-
continue
|
|
1493
|
-
|
|
1494
|
-
# Create prefixed parameter name for end node to avoid collisions
|
|
1495
|
-
end_param_name = f"{request.output_parameter_prefix}{package_param.name}"
|
|
1496
|
-
|
|
1497
|
-
# Extract parameter shape info for workflow shape (outputs to external consumers)
|
|
1498
|
-
param_shape_info = GriptapeNodes.WorkflowManager().extract_parameter_shape_info(
|
|
1499
|
-
package_param, include_control_params=True
|
|
1500
|
-
)
|
|
1501
|
-
if param_shape_info is not None:
|
|
1502
|
-
if end_node_name not in output_shape_data:
|
|
1503
|
-
output_shape_data[end_node_name] = {}
|
|
1504
|
-
output_shape_data[end_node_name][end_param_name] = param_shape_info
|
|
1505
|
-
|
|
1506
|
-
# Create parameter command for end node
|
|
1507
|
-
add_param_request = AddParameterToNodeRequest(
|
|
1508
|
-
node_name=end_node_name,
|
|
1509
|
-
parameter_name=end_param_name,
|
|
1510
|
-
# Use the package node's output_type as the type for our end node parameter
|
|
1511
|
-
type=package_param.output_type,
|
|
1512
|
-
default_value=None,
|
|
1513
|
-
tooltip=f"Output parameter {package_param.name} from packaged node {package_node.name}",
|
|
1514
|
-
initial_setup=True,
|
|
1515
|
-
)
|
|
1516
|
-
end_node_parameter_commands.append(add_param_request)
|
|
1517
|
-
|
|
1518
|
-
# Create connection from package node to end node
|
|
1519
|
-
package_to_end_connection = SerializedFlowCommands.IndirectConnectionSerialization(
|
|
1520
|
-
source_node_uuid=package_node_uuid,
|
|
1521
|
-
source_parameter_name=package_param.name,
|
|
1522
|
-
target_node_uuid=end_node_uuid,
|
|
1523
|
-
target_parameter_name=end_param_name,
|
|
1524
|
-
)
|
|
1525
|
-
package_to_end_connections.append(package_to_end_connection)
|
|
1526
|
-
|
|
1527
|
-
# Build complete SerializedNodeCommands for end node
|
|
1528
|
-
end_node_dependencies = NodeDependencies()
|
|
1529
|
-
end_node_dependencies.libraries.add(end_node_library_details)
|
|
1530
|
-
|
|
1531
|
-
end_node_commands = SerializedNodeCommands(
|
|
1532
|
-
create_node_command=end_create_node_command,
|
|
1533
|
-
element_modification_commands=end_node_parameter_commands,
|
|
1534
|
-
node_dependencies=end_node_dependencies,
|
|
1535
|
-
node_uuid=end_node_uuid,
|
|
1536
|
-
)
|
|
1537
|
-
|
|
1538
|
-
return PackagingEndNodeResult(
|
|
1539
|
-
end_node_commands=end_node_commands,
|
|
1540
|
-
package_to_end_connections=package_to_end_connections,
|
|
1541
|
-
output_shape_data=output_shape_data,
|
|
1542
|
-
)
|
|
1543
|
-
|
|
1544
|
-
def _assemble_serialized_flow( # noqa: PLR0913
|
|
1545
|
-
self,
|
|
1546
|
-
serialized_package_result: SerializeNodeToCommandsResultSuccess,
|
|
1547
|
-
start_node_result: PackagingStartNodeResult,
|
|
1548
|
-
end_node_result: PackagingEndNodeResult,
|
|
1549
|
-
control_flow_connections: list[SerializedFlowCommands.IndirectConnectionSerialization],
|
|
1550
|
-
unique_parameter_uuid_to_values: dict[SerializedNodeCommands.UniqueParameterValueUUID, Any],
|
|
1551
|
-
library_version: str,
|
|
1552
|
-
request: PackageNodeAsSerializedFlowRequest,
|
|
1553
|
-
) -> SerializedFlowCommands:
|
|
1554
|
-
"""Assemble the complete SerializedFlowCommands from all components."""
|
|
1555
|
-
# Combine all connections: Start->Package + Package->End + Control Flow
|
|
1556
|
-
all_connections = (
|
|
1557
|
-
start_node_result.start_to_package_connections
|
|
1558
|
-
+ end_node_result.package_to_end_connections
|
|
1559
|
-
+ control_flow_connections
|
|
1560
|
-
)
|
|
1561
|
-
|
|
1562
|
-
# Set up lock commands if needed
|
|
1563
|
-
set_lock_commands_per_node = {}
|
|
1564
|
-
if serialized_package_result.serialized_node_commands.lock_node_command:
|
|
1565
|
-
set_lock_commands_per_node[serialized_package_result.serialized_node_commands.node_uuid] = (
|
|
1566
|
-
serialized_package_result.serialized_node_commands.lock_node_command
|
|
1567
|
-
)
|
|
1568
|
-
|
|
1569
|
-
# Include all three nodes in the flow
|
|
1570
|
-
all_serialized_nodes = [
|
|
1571
|
-
start_node_result.start_node_commands,
|
|
1572
|
-
serialized_package_result.serialized_node_commands,
|
|
1573
|
-
end_node_result.end_node_commands,
|
|
1574
|
-
]
|
|
1575
|
-
|
|
1576
|
-
# Create a CreateFlowRequest for the packaged flow so that it can
|
|
1577
|
-
# run as a standalone workflow.
|
|
1578
|
-
package_flow_name = (
|
|
1579
|
-
f"Packaged_{serialized_package_result.serialized_node_commands.create_node_command.node_name}"
|
|
1580
|
-
)
|
|
1581
|
-
packaged_flow_metadata = {} # Keep it simple until we have reason to populate it
|
|
1582
|
-
|
|
1583
|
-
create_packaged_flow_request = CreateFlowRequest(
|
|
1584
|
-
parent_flow_name=None, # Standalone flow
|
|
1585
|
-
flow_name=package_flow_name,
|
|
1586
|
-
set_as_new_context=False, # Let deserializer decide
|
|
1587
|
-
metadata=packaged_flow_metadata,
|
|
1588
|
-
)
|
|
1589
|
-
|
|
1590
|
-
# Aggregate dependencies from the packaged nodes
|
|
1591
|
-
packaged_dependencies = self._aggregate_flow_dependencies(all_serialized_nodes, [])
|
|
1592
|
-
|
|
1593
|
-
# Add the start/end specific library dependency
|
|
1594
|
-
start_end_library_dependency = LibraryNameAndVersion(
|
|
1595
|
-
library_name=request.start_end_specific_library_name,
|
|
1596
|
-
library_version=library_version,
|
|
1597
|
-
)
|
|
1598
|
-
packaged_dependencies.libraries.add(start_end_library_dependency)
|
|
1599
|
-
|
|
1600
|
-
# Aggregate node types used
|
|
1601
|
-
packaged_node_types_used = self._aggregate_node_types_used(
|
|
1602
|
-
serialized_node_commands=all_serialized_nodes, sub_flows_commands=[]
|
|
1603
|
-
)
|
|
1604
|
-
|
|
1605
|
-
# Build the complete SerializedFlowCommands
|
|
1606
|
-
return SerializedFlowCommands(
|
|
1607
|
-
flow_initialization_command=create_packaged_flow_request,
|
|
1608
|
-
serialized_node_commands=all_serialized_nodes,
|
|
1609
|
-
serialized_connections=all_connections,
|
|
1610
|
-
unique_parameter_uuid_to_values=unique_parameter_uuid_to_values,
|
|
1611
|
-
set_parameter_value_commands={
|
|
1612
|
-
serialized_package_result.serialized_node_commands.node_uuid: serialized_package_result.set_parameter_value_commands,
|
|
1613
|
-
start_node_result.start_node_commands.node_uuid: start_node_result.start_node_parameter_value_commands,
|
|
1614
|
-
},
|
|
1615
|
-
set_lock_commands_per_node=set_lock_commands_per_node,
|
|
1616
|
-
sub_flows_commands=[],
|
|
1617
|
-
node_dependencies=packaged_dependencies,
|
|
1618
|
-
node_types_used=packaged_node_types_used,
|
|
1619
|
-
)
|
|
1620
|
-
|
|
1621
|
-
def on_package_nodes_as_serialized_flow_request( # noqa: C901, PLR0911
|
|
1106
|
+
def on_package_nodes_as_serialized_flow_request( # noqa: C901, PLR0911, PLR0912
|
|
1622
1107
|
self, request: PackageNodesAsSerializedFlowRequest
|
|
1623
1108
|
) -> ResultPayload:
|
|
1624
1109
|
"""Handle request to package multiple nodes as a serialized flow.
|
|
@@ -1626,6 +1111,12 @@ class FlowManager:
|
|
|
1626
1111
|
Creates a self-contained flow with Start → [Selected Nodes] → End structure,
|
|
1627
1112
|
where artificial start/end nodes interface with external connections only.
|
|
1628
1113
|
"""
|
|
1114
|
+
# Step 0: Apply defaults for None values
|
|
1115
|
+
if request.start_node_type is None:
|
|
1116
|
+
request.start_node_type = "StartFlow"
|
|
1117
|
+
if request.end_node_type is None:
|
|
1118
|
+
request.end_node_type = "EndFlow"
|
|
1119
|
+
|
|
1629
1120
|
# Step 1: Reject empty node list
|
|
1630
1121
|
if not request.node_names:
|
|
1631
1122
|
return PackageNodesAsSerializedFlowResultFailure(
|
|
@@ -1665,6 +1156,7 @@ class FlowManager:
|
|
|
1665
1156
|
node_name_to_uuid=node_name_to_uuid,
|
|
1666
1157
|
set_parameter_value_commands=packaged_nodes_set_parameter_value_commands,
|
|
1667
1158
|
internal_connections=packaged_nodes_internal_connections,
|
|
1159
|
+
proxy_node=request.proxy_node,
|
|
1668
1160
|
)
|
|
1669
1161
|
if isinstance(serialized_package_nodes, PackageNodesAsSerializedFlowResultFailure):
|
|
1670
1162
|
return serialized_package_nodes
|
|
@@ -1678,7 +1170,9 @@ class FlowManager:
|
|
|
1678
1170
|
self._inject_output_mode_for_property_parameters(nodes_to_package, serialized_package_nodes)
|
|
1679
1171
|
|
|
1680
1172
|
# Step 7: Analyze external connections (connections from/to nodes outside our selection)
|
|
1681
|
-
node_connections_dict = self._analyze_multi_node_external_connections(
|
|
1173
|
+
node_connections_dict = self._analyze_multi_node_external_connections(
|
|
1174
|
+
package_nodes=nodes_to_package, proxy_node=request.proxy_node
|
|
1175
|
+
)
|
|
1682
1176
|
if isinstance(node_connections_dict, PackageNodesAsSerializedFlowResultFailure):
|
|
1683
1177
|
return node_connections_dict
|
|
1684
1178
|
|
|
@@ -1789,7 +1283,8 @@ class FlowManager:
|
|
|
1789
1283
|
# Early validation - ensure both start and end node types exist in the specified library
|
|
1790
1284
|
try:
|
|
1791
1285
|
start_end_library = LibraryRegistry.get_library_for_node_type(
|
|
1792
|
-
node_type=request.start_node_type,
|
|
1286
|
+
node_type=request.start_node_type, # type: ignore[arg-type] # Guaranteed non-None by handler
|
|
1287
|
+
specific_library_name=request.start_end_specific_library_name,
|
|
1793
1288
|
)
|
|
1794
1289
|
except KeyError as err:
|
|
1795
1290
|
details = f"Attempted to package nodes with start node type '{request.start_node_type}' from library '{request.start_end_specific_library_name}'. Failed because start node type was not found in library. Error: {err}."
|
|
@@ -1797,7 +1292,8 @@ class FlowManager:
|
|
|
1797
1292
|
|
|
1798
1293
|
try:
|
|
1799
1294
|
LibraryRegistry.get_library_for_node_type(
|
|
1800
|
-
node_type=request.end_node_type,
|
|
1295
|
+
node_type=request.end_node_type, # type: ignore[arg-type] # Guaranteed non-None by handler
|
|
1296
|
+
specific_library_name=request.start_end_specific_library_name,
|
|
1801
1297
|
)
|
|
1802
1298
|
except KeyError as err:
|
|
1803
1299
|
details = f"Attempted to package nodes with end node type '{request.end_node_type}' from library '{request.start_end_specific_library_name}'. Failed because end node type was not found in library. Error: {err}."
|
|
@@ -1838,7 +1334,7 @@ class FlowManager:
|
|
|
1838
1334
|
|
|
1839
1335
|
return None
|
|
1840
1336
|
|
|
1841
|
-
def _serialize_package_nodes_for_local_execution( # noqa:
|
|
1337
|
+
def _serialize_package_nodes_for_local_execution( # noqa: PLR0913
|
|
1842
1338
|
self,
|
|
1843
1339
|
nodes_to_package: list[BaseNode],
|
|
1844
1340
|
unique_parameter_uuid_to_values: dict[SerializedNodeCommands.UniqueParameterValueUUID, Any],
|
|
@@ -1848,6 +1344,7 @@ class FlowManager:
|
|
|
1848
1344
|
SerializedNodeCommands.NodeUUID, list[SerializedNodeCommands.IndirectSetParameterValueCommand]
|
|
1849
1345
|
],
|
|
1850
1346
|
internal_connections: list[SerializedFlowCommands.IndirectConnectionSerialization], # OUTPUT: will be populated
|
|
1347
|
+
proxy_node: NodeGroupProxyNode | None = None, # NodeGroupProxyNode if packaging nodes from a proxy
|
|
1851
1348
|
) -> list[SerializedNodeCommands] | PackageNodesAsSerializedFlowResultFailure:
|
|
1852
1349
|
"""Serialize package nodes while temporarily setting execution environment to local to prevent recursive loops.
|
|
1853
1350
|
|
|
@@ -1862,17 +1359,26 @@ class FlowManager:
|
|
|
1862
1359
|
node_name_to_uuid: OUTPUT - Dictionary mapping node names to UUIDs (populated by this method)
|
|
1863
1360
|
set_parameter_value_commands: OUTPUT - Dict mapping node UUIDs to parameter value commands (populated by this method)
|
|
1864
1361
|
internal_connections: OUTPUT - List of connections between package nodes (populated by this method)
|
|
1362
|
+
proxy_node: NodeGroupProxyNode if packaging nodes from a proxy, provides access to original connections
|
|
1363
|
+
stored before they were redirected to the proxy
|
|
1865
1364
|
|
|
1866
1365
|
Returns:
|
|
1867
1366
|
List of SerializedNodeCommands on success, or PackageNodesAsSerializedFlowResultFailure on failure
|
|
1868
1367
|
"""
|
|
1869
|
-
# Intercept execution_environment for all nodes before serialization
|
|
1368
|
+
# Intercept execution_environment and job_group for all nodes before serialization
|
|
1870
1369
|
original_execution_environments = {}
|
|
1370
|
+
original_job_groups = {}
|
|
1871
1371
|
for node in nodes_to_package:
|
|
1872
|
-
|
|
1873
|
-
|
|
1372
|
+
# Save and override execution_environment to prevent recursive packaging loops
|
|
1373
|
+
original_exec_value = node.get_parameter_value("execution_environment")
|
|
1374
|
+
original_execution_environments[node.name] = original_exec_value
|
|
1874
1375
|
node.set_parameter_value("execution_environment", LOCAL_EXECUTION)
|
|
1875
1376
|
|
|
1377
|
+
# Save and clear job_group to prevent group processing in packaged flow
|
|
1378
|
+
original_job_group_value = node.get_parameter_value("job_group")
|
|
1379
|
+
original_job_groups[node.name] = original_job_group_value
|
|
1380
|
+
node.set_parameter_value("job_group", "")
|
|
1381
|
+
|
|
1876
1382
|
try:
|
|
1877
1383
|
# Serialize each node using shared unique_parameter_uuid_to_values dictionary for deduplication
|
|
1878
1384
|
serialized_node_commands = []
|
|
@@ -1908,8 +1414,134 @@ class FlowManager:
|
|
|
1908
1414
|
|
|
1909
1415
|
# Build internal connections between package nodes
|
|
1910
1416
|
package_node_names_set = {n.name for n in nodes_to_package}
|
|
1417
|
+
|
|
1418
|
+
# Get connections using appropriate method based on whether we have a proxy node
|
|
1419
|
+
connections_result = self._get_internal_connections_for_package(
|
|
1420
|
+
nodes_to_package=nodes_to_package,
|
|
1421
|
+
package_node_names_set=package_node_names_set,
|
|
1422
|
+
node_name_to_uuid=node_name_to_uuid,
|
|
1423
|
+
proxy_node=proxy_node,
|
|
1424
|
+
)
|
|
1425
|
+
|
|
1426
|
+
if isinstance(connections_result, PackageNodesAsSerializedFlowResultFailure):
|
|
1427
|
+
return connections_result
|
|
1428
|
+
|
|
1429
|
+
internal_connections.extend(connections_result)
|
|
1430
|
+
finally:
|
|
1431
|
+
# Always restore original execution_environment and job_group values, even on failure
|
|
1432
|
+
for node_name, original_value in original_execution_environments.items():
|
|
1433
|
+
restore_node = GriptapeNodes.NodeManager().get_node_by_name(node_name)
|
|
1434
|
+
restore_node.set_parameter_value("execution_environment", original_value)
|
|
1435
|
+
|
|
1436
|
+
for node_name, original_job_group in original_job_groups.items():
|
|
1437
|
+
restore_node = GriptapeNodes.NodeManager().get_node_by_name(node_name)
|
|
1438
|
+
restore_node.set_parameter_value("job_group", original_job_group)
|
|
1439
|
+
|
|
1440
|
+
return serialized_node_commands
|
|
1441
|
+
|
|
1442
|
+
def _get_internal_connections_for_package( # noqa: C901, PLR0912
|
|
1443
|
+
self,
|
|
1444
|
+
nodes_to_package: list[BaseNode],
|
|
1445
|
+
package_node_names_set: set[str],
|
|
1446
|
+
node_name_to_uuid: dict[str, SerializedNodeCommands.NodeUUID],
|
|
1447
|
+
proxy_node: NodeGroupProxyNode | None,
|
|
1448
|
+
) -> list[SerializedFlowCommands.IndirectConnectionSerialization] | PackageNodesAsSerializedFlowResultFailure:
|
|
1449
|
+
"""Get internal connections between package nodes.
|
|
1450
|
+
|
|
1451
|
+
If a proxy_node is provided, uses the stored internal_connections from the NodeGroup
|
|
1452
|
+
which preserve the original connection structure before redirection to the proxy.
|
|
1453
|
+
Otherwise, queries connections from the connection manager.
|
|
1454
|
+
|
|
1455
|
+
Args:
|
|
1456
|
+
nodes_to_package: List of nodes being packaged
|
|
1457
|
+
package_node_names_set: Set of node names in the package for O(1) lookup
|
|
1458
|
+
node_name_to_uuid: Mapping of node names to their UUIDs in the serialization
|
|
1459
|
+
proxy_node: Optional proxy node containing the original connection structure
|
|
1460
|
+
|
|
1461
|
+
Returns:
|
|
1462
|
+
List of serialized connections, or PackageNodesAsSerializedFlowResultFailure on error
|
|
1463
|
+
"""
|
|
1464
|
+
internal_connections: list[SerializedFlowCommands.IndirectConnectionSerialization] = []
|
|
1465
|
+
|
|
1466
|
+
if proxy_node is not None and hasattr(proxy_node, "node_group_data"):
|
|
1467
|
+
# Use stored connections from NodeGroup which have the original node references
|
|
1468
|
+
node_group = proxy_node.node_group_data
|
|
1469
|
+
|
|
1470
|
+
# 1. Add internal connections (between nodes inside the group)
|
|
1471
|
+
for conn in node_group.internal_connections:
|
|
1472
|
+
source_node_name = conn.source_node.name
|
|
1473
|
+
target_node_name = conn.target_node.name
|
|
1474
|
+
|
|
1475
|
+
# Only include connections where BOTH nodes are in our package
|
|
1476
|
+
if source_node_name in package_node_names_set and target_node_name in package_node_names_set:
|
|
1477
|
+
source_uuid = node_name_to_uuid[source_node_name]
|
|
1478
|
+
target_uuid = node_name_to_uuid[target_node_name]
|
|
1479
|
+
internal_connections.append(
|
|
1480
|
+
SerializedFlowCommands.IndirectConnectionSerialization(
|
|
1481
|
+
source_node_uuid=source_uuid,
|
|
1482
|
+
source_parameter_name=conn.source_parameter.name,
|
|
1483
|
+
target_node_uuid=target_uuid,
|
|
1484
|
+
target_parameter_name=conn.target_parameter.name,
|
|
1485
|
+
)
|
|
1486
|
+
)
|
|
1487
|
+
|
|
1488
|
+
# 2. Add external incoming connections (from outside into the group)
|
|
1489
|
+
# These connections have been redirected to point TO the proxy, but we want the original targets
|
|
1490
|
+
for conn in node_group.external_incoming_connections:
|
|
1491
|
+
conn_id = id(conn)
|
|
1492
|
+
original_target = node_group.original_incoming_targets.get(conn_id)
|
|
1493
|
+
|
|
1494
|
+
if original_target and original_target.name in package_node_names_set:
|
|
1495
|
+
# The source is outside the package, target is inside
|
|
1496
|
+
# We include these because the source will be external (like StartFlow)
|
|
1497
|
+
source_node_name = conn.source_node.name
|
|
1498
|
+
target_node_name = original_target.name
|
|
1499
|
+
|
|
1500
|
+
# Only include if source is NOT in package (external) and target IS in package
|
|
1501
|
+
if source_node_name not in package_node_names_set:
|
|
1502
|
+
source_uuid = node_name_to_uuid.get(source_node_name)
|
|
1503
|
+
target_uuid = node_name_to_uuid[target_node_name]
|
|
1504
|
+
|
|
1505
|
+
# Source might not have a UUID if it's external to the package
|
|
1506
|
+
if source_uuid:
|
|
1507
|
+
internal_connections.append(
|
|
1508
|
+
SerializedFlowCommands.IndirectConnectionSerialization(
|
|
1509
|
+
source_node_uuid=source_uuid,
|
|
1510
|
+
source_parameter_name=conn.source_parameter.name,
|
|
1511
|
+
target_node_uuid=target_uuid,
|
|
1512
|
+
target_parameter_name=conn.target_parameter.name,
|
|
1513
|
+
)
|
|
1514
|
+
)
|
|
1515
|
+
|
|
1516
|
+
# 3. Add external outgoing connections (from the group to outside)
|
|
1517
|
+
# These connections have been redirected to point FROM the proxy, but we want the original sources
|
|
1518
|
+
for conn in node_group.external_outgoing_connections:
|
|
1519
|
+
conn_id = id(conn)
|
|
1520
|
+
original_source = node_group.original_outgoing_sources.get(conn_id)
|
|
1521
|
+
|
|
1522
|
+
if original_source and original_source.name in package_node_names_set:
|
|
1523
|
+
# The source is inside the package, target is outside
|
|
1524
|
+
source_node_name = original_source.name
|
|
1525
|
+
target_node_name = conn.target_node.name
|
|
1526
|
+
|
|
1527
|
+
# Only include if source IS in package and target is NOT in package (external)
|
|
1528
|
+
if target_node_name not in package_node_names_set:
|
|
1529
|
+
source_uuid = node_name_to_uuid[source_node_name]
|
|
1530
|
+
target_uuid = node_name_to_uuid.get(target_node_name)
|
|
1531
|
+
|
|
1532
|
+
# Target might not have a UUID if it's external to the package
|
|
1533
|
+
if target_uuid:
|
|
1534
|
+
internal_connections.append(
|
|
1535
|
+
SerializedFlowCommands.IndirectConnectionSerialization(
|
|
1536
|
+
source_node_uuid=source_uuid,
|
|
1537
|
+
source_parameter_name=conn.source_parameter.name,
|
|
1538
|
+
target_node_uuid=target_uuid,
|
|
1539
|
+
target_parameter_name=conn.target_parameter.name,
|
|
1540
|
+
)
|
|
1541
|
+
)
|
|
1542
|
+
else:
|
|
1543
|
+
# No proxy node - query connections from connection manager
|
|
1911
1544
|
for node in nodes_to_package:
|
|
1912
|
-
# Get connections FROM this node TO other nodes in the package
|
|
1913
1545
|
list_connections_request = ListConnectionsForNodeRequest(node_name=node.name)
|
|
1914
1546
|
list_connections_result = GriptapeNodes.NodeManager().on_list_connections_for_node_request(
|
|
1915
1547
|
list_connections_request
|
|
@@ -1933,13 +1565,8 @@ class FlowManager:
|
|
|
1933
1565
|
target_parameter_name=outgoing_conn.target_parameter_name,
|
|
1934
1566
|
)
|
|
1935
1567
|
)
|
|
1936
|
-
finally:
|
|
1937
|
-
# Always restore original execution_environment values, even on failure
|
|
1938
|
-
for node_name, original_value in original_execution_environments.items():
|
|
1939
|
-
restore_node = GriptapeNodes.NodeManager().get_node_by_name(node_name)
|
|
1940
|
-
restore_node.set_parameter_value("execution_environment", original_value)
|
|
1941
1568
|
|
|
1942
|
-
return
|
|
1569
|
+
return internal_connections
|
|
1943
1570
|
|
|
1944
1571
|
def _inject_output_mode_for_property_parameters(
|
|
1945
1572
|
self, nodes_to_package: list[BaseNode], serialized_package_nodes: list[SerializedNodeCommands]
|
|
@@ -1988,7 +1615,7 @@ class FlowManager:
|
|
|
1988
1615
|
serialized_node.element_modification_commands.extend(package_alter_parameter_commands)
|
|
1989
1616
|
|
|
1990
1617
|
def _analyze_multi_node_external_connections(
|
|
1991
|
-
self, package_nodes: list[BaseNode]
|
|
1618
|
+
self, package_nodes: list[BaseNode], proxy_node: NodeGroupProxyNode | None = None
|
|
1992
1619
|
) -> dict[str, ConnectionAnalysis] | PackageNodesAsSerializedFlowResultFailure:
|
|
1993
1620
|
"""Analyze external connections for each package node using filtered single-node analysis.
|
|
1994
1621
|
|
|
@@ -2004,6 +1631,7 @@ class FlowManager:
|
|
|
2004
1631
|
|
|
2005
1632
|
Args:
|
|
2006
1633
|
package_nodes: List of nodes being packaged together
|
|
1634
|
+
proxy_node: Optional proxy node containing the original connection structure
|
|
2007
1635
|
|
|
2008
1636
|
Returns:
|
|
2009
1637
|
Dictionary mapping node_name -> ConnectionAnalysis, where each ConnectionAnalysis
|
|
@@ -2018,32 +1646,126 @@ class FlowManager:
|
|
|
2018
1646
|
package_node=package_node,
|
|
2019
1647
|
node_name=package_node.name,
|
|
2020
1648
|
package_node_names=package_node_names_set,
|
|
1649
|
+
proxy_node=proxy_node,
|
|
2021
1650
|
)
|
|
2022
|
-
if isinstance(connection_analysis,
|
|
1651
|
+
if isinstance(connection_analysis, PackageNodesAsSerializedFlowResultFailure):
|
|
2023
1652
|
return PackageNodesAsSerializedFlowResultFailure(result_details=connection_analysis.result_details)
|
|
2024
1653
|
|
|
2025
1654
|
node_connections[package_node.name] = connection_analysis
|
|
2026
1655
|
|
|
2027
1656
|
return node_connections
|
|
2028
1657
|
|
|
2029
|
-
def
|
|
2030
|
-
self,
|
|
2031
|
-
) ->
|
|
2032
|
-
"""
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
1658
|
+
def _get_node_connections_from_proxy(
|
|
1659
|
+
self, node_name: str, proxy_node: NodeGroupProxyNode
|
|
1660
|
+
) -> tuple[list[IncomingConnection], list[OutgoingConnection]]:
|
|
1661
|
+
"""Extract incoming and outgoing connections for a specific node from the proxy node's stored data.
|
|
1662
|
+
|
|
1663
|
+
Returns connections in the same format as ListConnectionsForNodeRequest would return them,
|
|
1664
|
+
using the original node references from before proxy redirection.
|
|
1665
|
+
|
|
1666
|
+
Args:
|
|
1667
|
+
node_name: Name of the node to get connections for
|
|
1668
|
+
proxy_node: The proxy node containing the NodeGroup data with stored connections
|
|
1669
|
+
|
|
1670
|
+
Returns:
|
|
1671
|
+
Tuple of (incoming_connections, outgoing_connections) matching the ListConnectionsForNodeResultSuccess format
|
|
1672
|
+
"""
|
|
1673
|
+
node_group = proxy_node.node_group_data
|
|
1674
|
+
incoming_connections: list[IncomingConnection] = []
|
|
1675
|
+
outgoing_connections: list[OutgoingConnection] = []
|
|
1676
|
+
|
|
1677
|
+
# Get incoming connections: check internal_connections and external_incoming_connections
|
|
1678
|
+
# Internal connections where this node is the target
|
|
1679
|
+
incoming_connections.extend(
|
|
1680
|
+
IncomingConnection(
|
|
1681
|
+
source_node_name=conn.source_node.name,
|
|
1682
|
+
source_parameter_name=conn.source_parameter.name,
|
|
1683
|
+
target_parameter_name=conn.target_parameter.name,
|
|
1684
|
+
)
|
|
1685
|
+
for conn in node_group.internal_connections
|
|
1686
|
+
if conn.target_node.name == node_name
|
|
1687
|
+
)
|
|
1688
|
+
|
|
1689
|
+
# External incoming connections where this node is the original target
|
|
1690
|
+
incoming_connections.extend(
|
|
1691
|
+
IncomingConnection(
|
|
1692
|
+
source_node_name=conn.source_node.name,
|
|
1693
|
+
source_parameter_name=conn.source_parameter.name,
|
|
1694
|
+
target_parameter_name=conn.target_parameter.name,
|
|
1695
|
+
)
|
|
1696
|
+
for conn in node_group.external_incoming_connections
|
|
1697
|
+
if (original_target := node_group.original_incoming_targets.get(id(conn)))
|
|
1698
|
+
and original_target.name == node_name
|
|
1699
|
+
)
|
|
1700
|
+
|
|
1701
|
+
# Get outgoing connections: check internal_connections and external_outgoing_connections
|
|
1702
|
+
# Internal connections where this node is the source
|
|
1703
|
+
outgoing_connections.extend(
|
|
1704
|
+
OutgoingConnection(
|
|
1705
|
+
source_parameter_name=conn.source_parameter.name,
|
|
1706
|
+
target_node_name=conn.target_node.name,
|
|
1707
|
+
target_parameter_name=conn.target_parameter.name,
|
|
1708
|
+
)
|
|
1709
|
+
for conn in node_group.internal_connections
|
|
1710
|
+
if conn.source_node.name == node_name
|
|
2037
1711
|
)
|
|
2038
1712
|
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
1713
|
+
# External outgoing connections where this node is the original source
|
|
1714
|
+
outgoing_connections.extend(
|
|
1715
|
+
OutgoingConnection(
|
|
1716
|
+
source_parameter_name=conn.source_parameter.name,
|
|
1717
|
+
target_node_name=conn.target_node.name,
|
|
1718
|
+
target_parameter_name=conn.target_parameter.name,
|
|
1719
|
+
)
|
|
1720
|
+
for conn in node_group.external_outgoing_connections
|
|
1721
|
+
if (original_source := node_group.original_outgoing_sources.get(id(conn)))
|
|
1722
|
+
and original_source.name == node_name
|
|
1723
|
+
)
|
|
1724
|
+
|
|
1725
|
+
return incoming_connections, outgoing_connections
|
|
1726
|
+
|
|
1727
|
+
def _analyze_package_node_connections(
|
|
1728
|
+
self,
|
|
1729
|
+
package_node: BaseNode,
|
|
1730
|
+
node_name: str,
|
|
1731
|
+
package_node_names: set[str] | None = None,
|
|
1732
|
+
proxy_node: NodeGroupProxyNode | None = None,
|
|
1733
|
+
) -> ConnectionAnalysis | PackageNodesAsSerializedFlowResultFailure:
|
|
1734
|
+
"""Analyze package node connections and separate control from data connections.
|
|
1735
|
+
|
|
1736
|
+
If a proxy_node is provided, uses the stored connections from the NodeGroup which preserve
|
|
1737
|
+
the original connection structure before proxy redirection.
|
|
1738
|
+
|
|
1739
|
+
Args:
|
|
1740
|
+
package_node: The node being analyzed
|
|
1741
|
+
node_name: Name of the node
|
|
1742
|
+
package_node_names: Set of node names in the package for filtering internal connections
|
|
1743
|
+
proxy_node: Optional proxy node containing original connection structure
|
|
1744
|
+
"""
|
|
1745
|
+
# Get incoming and outgoing connections for this node
|
|
1746
|
+
if proxy_node is not None and hasattr(proxy_node, "node_group_data"):
|
|
1747
|
+
# Use stored connections from proxy which have the original node references
|
|
1748
|
+
incoming_connections, outgoing_connections = self._get_node_connections_from_proxy(
|
|
1749
|
+
node_name=node_name, proxy_node=proxy_node
|
|
1750
|
+
)
|
|
1751
|
+
else:
|
|
1752
|
+
# Get connection details using the standard approach
|
|
1753
|
+
list_connections_request = ListConnectionsForNodeRequest(node_name=node_name)
|
|
1754
|
+
list_connections_result = GriptapeNodes.NodeManager().on_list_connections_for_node_request(
|
|
1755
|
+
list_connections_request
|
|
1756
|
+
)
|
|
1757
|
+
|
|
1758
|
+
if not isinstance(list_connections_result, ListConnectionsForNodeResultSuccess):
|
|
1759
|
+
details = f"Attempted to analyze connections for package node '{node_name}'. Failed because connection listing failed."
|
|
1760
|
+
return PackageNodesAsSerializedFlowResultFailure(result_details=details)
|
|
1761
|
+
|
|
1762
|
+
incoming_connections = list_connections_result.incoming_connections
|
|
1763
|
+
outgoing_connections = list_connections_result.outgoing_connections
|
|
2042
1764
|
|
|
2043
1765
|
# Separate control connections from data connections based on package node's parameter types
|
|
2044
1766
|
incoming_data_connections = []
|
|
2045
1767
|
incoming_control_connections = []
|
|
2046
|
-
for incoming_conn in
|
|
1768
|
+
for incoming_conn in incoming_connections:
|
|
2047
1769
|
# Filter out internal connections if package_node_names is provided
|
|
2048
1770
|
if package_node_names is not None and incoming_conn.source_node_name in package_node_names:
|
|
2049
1771
|
continue
|
|
@@ -2057,7 +1779,7 @@ class FlowManager:
|
|
|
2057
1779
|
|
|
2058
1780
|
outgoing_data_connections = []
|
|
2059
1781
|
outgoing_control_connections = []
|
|
2060
|
-
for outgoing_conn in
|
|
1782
|
+
for outgoing_conn in outgoing_connections:
|
|
2061
1783
|
# Filter out internal connections if package_node_names is provided
|
|
2062
1784
|
if package_node_names is not None and outgoing_conn.target_node_name in package_node_names:
|
|
2063
1785
|
continue
|
|
@@ -2091,7 +1813,7 @@ class FlowManager:
|
|
|
2091
1813
|
|
|
2092
1814
|
# Build end node CreateNodeRequest
|
|
2093
1815
|
end_create_node_command = CreateNodeRequest(
|
|
2094
|
-
node_type=request.end_node_type,
|
|
1816
|
+
node_type=request.end_node_type, # type: ignore[arg-type] # Guaranteed non-None by handler
|
|
2095
1817
|
specific_library_name=request.start_end_specific_library_name,
|
|
2096
1818
|
node_name=end_node_name,
|
|
2097
1819
|
metadata={},
|
|
@@ -2344,7 +2066,7 @@ class FlowManager:
|
|
|
2344
2066
|
|
|
2345
2067
|
# Build start node CreateNodeRequest
|
|
2346
2068
|
start_create_node_command = CreateNodeRequest(
|
|
2347
|
-
node_type=request.start_node_type,
|
|
2069
|
+
node_type=request.start_node_type, # type: ignore[arg-type] # Guaranteed non-None by handler
|
|
2348
2070
|
specific_library_name=request.start_end_specific_library_name,
|
|
2349
2071
|
node_name=start_node_name,
|
|
2350
2072
|
metadata={},
|
|
@@ -2555,7 +2277,7 @@ class FlowManager:
|
|
|
2555
2277
|
package_node_uuid=entry_node_uuid,
|
|
2556
2278
|
package_node=entry_node,
|
|
2557
2279
|
)
|
|
2558
|
-
if isinstance(control_connection_result,
|
|
2280
|
+
if isinstance(control_connection_result, PackageNodesAsSerializedFlowResultFailure):
|
|
2559
2281
|
return PackageNodesAsSerializedFlowResultFailure(
|
|
2560
2282
|
result_details=control_connection_result.result_details
|
|
2561
2283
|
)
|
|
@@ -2570,7 +2292,7 @@ class FlowManager:
|
|
|
2570
2292
|
start_node_uuid: SerializedNodeCommands.NodeUUID,
|
|
2571
2293
|
package_node_uuid: SerializedNodeCommands.NodeUUID,
|
|
2572
2294
|
package_node: BaseNode,
|
|
2573
|
-
) -> SerializedFlowCommands.IndirectConnectionSerialization |
|
|
2295
|
+
) -> SerializedFlowCommands.IndirectConnectionSerialization | PackageNodesAsSerializedFlowResultFailure:
|
|
2574
2296
|
"""Create control flow connection from start node to package node.
|
|
2575
2297
|
|
|
2576
2298
|
Connects the start node's first control output to the specified or first available package node control input.
|
|
@@ -2594,7 +2316,7 @@ class FlowManager:
|
|
|
2594
2316
|
|
|
2595
2317
|
if package_control_input_name is None:
|
|
2596
2318
|
details = f"Attempted to package node '{package_node.name}'. Failed because no control input parameters found on the node, so cannot create control flow connection."
|
|
2597
|
-
return
|
|
2319
|
+
return PackageNodesAsSerializedFlowResultFailure(result_details=details)
|
|
2598
2320
|
|
|
2599
2321
|
# StartNode always has a control output parameter with name "exec_out"
|
|
2600
2322
|
source_control_parameter_name = "exec_out"
|
|
@@ -2740,7 +2462,7 @@ class FlowManager:
|
|
|
2740
2462
|
details = f"Could not get flow state. Error: {err}"
|
|
2741
2463
|
return GetFlowStateResultFailure(result_details=details)
|
|
2742
2464
|
try:
|
|
2743
|
-
control_nodes, resolving_nodes = self.flow_state(flow)
|
|
2465
|
+
control_nodes, resolving_nodes, involved_nodes = self.flow_state(flow)
|
|
2744
2466
|
except Exception as e:
|
|
2745
2467
|
details = f"Failed to get flow state of flow with name {flow_name}. Exception occurred: {e} "
|
|
2746
2468
|
logger.exception(details)
|
|
@@ -2748,7 +2470,8 @@ class FlowManager:
|
|
|
2748
2470
|
details = f"Successfully got flow state for flow with name {flow_name}."
|
|
2749
2471
|
return GetFlowStateResultSuccess(
|
|
2750
2472
|
control_nodes=control_nodes,
|
|
2751
|
-
|
|
2473
|
+
resolving_nodes=resolving_nodes,
|
|
2474
|
+
involved_nodes=involved_nodes,
|
|
2752
2475
|
result_details=details,
|
|
2753
2476
|
)
|
|
2754
2477
|
|
|
@@ -3318,9 +3041,11 @@ class FlowManager:
|
|
|
3318
3041
|
)
|
|
3319
3042
|
# Set off the request here.
|
|
3320
3043
|
try:
|
|
3321
|
-
await self._global_control_flow_machine.start_flow(start_node, debug_mode)
|
|
3044
|
+
await self._global_control_flow_machine.start_flow(start_node, debug_mode=debug_mode)
|
|
3322
3045
|
except Exception:
|
|
3323
3046
|
if self.check_for_existing_running_flow():
|
|
3047
|
+
# Cleanup proxy nodes before canceling flow
|
|
3048
|
+
self._global_control_flow_machine.cleanup_proxy_nodes()
|
|
3324
3049
|
await self.cancel_flow_run()
|
|
3325
3050
|
raise
|
|
3326
3051
|
GriptapeNodes.EventManager().put_event(
|
|
@@ -3349,6 +3074,10 @@ class FlowManager:
|
|
|
3349
3074
|
if self._global_control_flow_machine is not None:
|
|
3350
3075
|
await self._global_control_flow_machine.cancel_flow()
|
|
3351
3076
|
|
|
3077
|
+
# Cleanup proxy nodes and restore connections
|
|
3078
|
+
if self._global_control_flow_machine is not None:
|
|
3079
|
+
self._global_control_flow_machine.cleanup_proxy_nodes()
|
|
3080
|
+
|
|
3352
3081
|
# Reset control flow machine
|
|
3353
3082
|
if self._global_control_flow_machine is not None:
|
|
3354
3083
|
self._global_control_flow_machine.reset_machine(cancel=True)
|
|
@@ -3366,8 +3095,12 @@ class FlowManager:
|
|
|
3366
3095
|
def reset_global_execution_state(self) -> None:
|
|
3367
3096
|
"""Reset all global execution state - useful when clearing all workflows."""
|
|
3368
3097
|
self._global_flow_queue.queue.clear()
|
|
3098
|
+
|
|
3099
|
+
# Cleanup proxy nodes and restore connections before resetting machine
|
|
3369
3100
|
if self._global_control_flow_machine is not None:
|
|
3101
|
+
self._global_control_flow_machine.cleanup_proxy_nodes()
|
|
3370
3102
|
self._global_control_flow_machine.reset_machine()
|
|
3103
|
+
|
|
3371
3104
|
# Reset control flow machine
|
|
3372
3105
|
self._global_single_node_resolution = False
|
|
3373
3106
|
|
|
@@ -3423,7 +3156,7 @@ class FlowManager:
|
|
|
3423
3156
|
# Get or create machine
|
|
3424
3157
|
if self._global_control_flow_machine is None:
|
|
3425
3158
|
self._global_control_flow_machine = ControlFlowMachine(flow.name)
|
|
3426
|
-
await self._global_control_flow_machine.start_flow(start_node, debug_mode)
|
|
3159
|
+
await self._global_control_flow_machine.start_flow(start_node, debug_mode=debug_mode)
|
|
3427
3160
|
|
|
3428
3161
|
async def _handle_post_execution_queue_processing(self, *, debug_mode: bool) -> None:
|
|
3429
3162
|
"""Handle execution queue processing after execution completes."""
|
|
@@ -3433,7 +3166,7 @@ class FlowManager:
|
|
|
3433
3166
|
self._global_flow_queue.task_done()
|
|
3434
3167
|
machine = self._global_control_flow_machine
|
|
3435
3168
|
if machine is not None:
|
|
3436
|
-
await machine.start_flow(start_node, debug_mode)
|
|
3169
|
+
await machine.start_flow(start_node, debug_mode=debug_mode)
|
|
3437
3170
|
|
|
3438
3171
|
async def resolve_singular_node(self, flow: ControlFlow, node: BaseNode, *, debug_mode: bool = False) -> None:
|
|
3439
3172
|
# We are now going to have different behavior depending on how the node is behaving.
|
|
@@ -3471,10 +3204,14 @@ class FlowManager:
|
|
|
3471
3204
|
)
|
|
3472
3205
|
)
|
|
3473
3206
|
try:
|
|
3474
|
-
await
|
|
3207
|
+
await self._global_control_flow_machine.start_flow(
|
|
3208
|
+
start_node=node, end_node=node, debug_mode=debug_mode
|
|
3209
|
+
)
|
|
3475
3210
|
except Exception as e:
|
|
3476
3211
|
logger.exception("Exception during single node resolution")
|
|
3477
3212
|
if self.check_for_existing_running_flow():
|
|
3213
|
+
if self._global_control_flow_machine is not None:
|
|
3214
|
+
self._global_control_flow_machine.cleanup_proxy_nodes()
|
|
3478
3215
|
await self.cancel_flow_run()
|
|
3479
3216
|
raise RuntimeError(e) from e
|
|
3480
3217
|
if resolution_machine.is_complete():
|
|
@@ -3540,29 +3277,35 @@ class FlowManager:
|
|
|
3540
3277
|
# Clear entry control parameter for new execution
|
|
3541
3278
|
node.set_entry_control_parameter(None)
|
|
3542
3279
|
|
|
3543
|
-
def flow_state(self, flow: ControlFlow) -> tuple[list[str]
|
|
3280
|
+
def flow_state(self, flow: ControlFlow) -> tuple[list[str], list[str], list[str]]:
|
|
3544
3281
|
if not self.check_for_existing_running_flow():
|
|
3545
|
-
return
|
|
3282
|
+
return [], [], []
|
|
3546
3283
|
if self._global_control_flow_machine is None:
|
|
3547
|
-
return
|
|
3284
|
+
return [], [], []
|
|
3548
3285
|
control_flow_context = self._global_control_flow_machine.context
|
|
3549
3286
|
current_control_nodes = (
|
|
3550
3287
|
[control_flow_node.name for control_flow_node in control_flow_context.current_nodes]
|
|
3551
3288
|
if control_flow_context.current_nodes is not None
|
|
3552
|
-
else
|
|
3289
|
+
else []
|
|
3553
3290
|
)
|
|
3291
|
+
if self._global_single_node_resolution and isinstance(
|
|
3292
|
+
control_flow_context.resolution_machine, ParallelResolutionMachine
|
|
3293
|
+
):
|
|
3294
|
+
involved_nodes = list(self._global_dag_builder.node_to_reference.keys())
|
|
3295
|
+
else:
|
|
3296
|
+
involved_nodes = list(flow.nodes.keys())
|
|
3554
3297
|
# focus_stack is no longer available in the new architecture
|
|
3555
3298
|
if isinstance(control_flow_context.resolution_machine, ParallelResolutionMachine):
|
|
3556
3299
|
current_resolving_nodes = [
|
|
3557
3300
|
node.node_reference.name
|
|
3558
3301
|
for node in control_flow_context.resolution_machine.context.task_to_node.values()
|
|
3559
3302
|
]
|
|
3560
|
-
return current_control_nodes, current_resolving_nodes
|
|
3303
|
+
return current_control_nodes, current_resolving_nodes, involved_nodes
|
|
3561
3304
|
if isinstance(control_flow_context.resolution_machine, SequentialResolutionMachine):
|
|
3562
3305
|
focus_stack_for_node = control_flow_context.resolution_machine.context.focus_stack
|
|
3563
3306
|
current_resolving_node = focus_stack_for_node[-1].node.name if len(focus_stack_for_node) else None
|
|
3564
|
-
return current_control_nodes, [current_resolving_node] if current_resolving_node else
|
|
3565
|
-
return current_control_nodes,
|
|
3307
|
+
return current_control_nodes, [current_resolving_node] if current_resolving_node else [], involved_nodes
|
|
3308
|
+
return current_control_nodes, [], involved_nodes
|
|
3566
3309
|
|
|
3567
3310
|
def get_start_node_from_node(self, flow: ControlFlow, node: BaseNode) -> BaseNode | None:
|
|
3568
3311
|
# backwards chain in control outputs.
|