griptape-nodes 0.37.1__py3-none-any.whl → 0.38.0__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/__init__.py +292 -132
- griptape_nodes/app/__init__.py +1 -6
- griptape_nodes/app/app.py +108 -76
- griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +80 -5
- griptape_nodes/drivers/storage/local_storage_driver.py +5 -1
- griptape_nodes/exe_types/core_types.py +84 -3
- griptape_nodes/exe_types/node_types.py +260 -50
- griptape_nodes/machines/node_resolution.py +2 -14
- griptape_nodes/retained_mode/events/agent_events.py +7 -0
- griptape_nodes/retained_mode/events/base_events.py +16 -0
- griptape_nodes/retained_mode/events/library_events.py +26 -0
- griptape_nodes/retained_mode/events/parameter_events.py +31 -0
- griptape_nodes/retained_mode/griptape_nodes.py +32 -0
- griptape_nodes/retained_mode/managers/agent_manager.py +25 -12
- griptape_nodes/retained_mode/managers/config_manager.py +37 -4
- griptape_nodes/retained_mode/managers/event_manager.py +15 -0
- griptape_nodes/retained_mode/managers/flow_manager.py +64 -61
- griptape_nodes/retained_mode/managers/library_manager.py +215 -45
- griptape_nodes/retained_mode/managers/node_manager.py +344 -147
- griptape_nodes/retained_mode/managers/operation_manager.py +6 -0
- griptape_nodes/retained_mode/managers/os_manager.py +6 -1
- griptape_nodes/retained_mode/managers/secrets_manager.py +7 -2
- griptape_nodes/retained_mode/managers/settings.py +2 -11
- griptape_nodes/retained_mode/managers/static_files_manager.py +12 -3
- griptape_nodes/retained_mode/managers/version_compatibility_manager.py +105 -0
- griptape_nodes/retained_mode/managers/workflow_manager.py +4 -4
- griptape_nodes/updater/__init__.py +14 -8
- griptape_nodes/version_compatibility/__init__.py +1 -0
- griptape_nodes/version_compatibility/versions/__init__.py +1 -0
- griptape_nodes/version_compatibility/versions/v0_39_0/__init__.py +1 -0
- griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +77 -0
- {griptape_nodes-0.37.1.dist-info → griptape_nodes-0.38.0.dist-info}/METADATA +4 -1
- {griptape_nodes-0.37.1.dist-info → griptape_nodes-0.38.0.dist-info}/RECORD +36 -33
- griptape_nodes/app/app_websocket.py +0 -481
- griptape_nodes/app/nodes_api_socket_manager.py +0 -117
- {griptape_nodes-0.37.1.dist-info → griptape_nodes-0.38.0.dist-info}/WHEEL +0 -0
- {griptape_nodes-0.37.1.dist-info → griptape_nodes-0.38.0.dist-info}/entry_points.txt +0 -0
- {griptape_nodes-0.37.1.dist-info → griptape_nodes-0.38.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -4,12 +4,11 @@ import pickle
|
|
|
4
4
|
from typing import Any, NamedTuple, cast
|
|
5
5
|
from uuid import uuid4
|
|
6
6
|
|
|
7
|
-
from griptape.events import EventBus
|
|
8
|
-
|
|
9
7
|
from griptape_nodes.exe_types.core_types import (
|
|
10
8
|
BaseNodeElement,
|
|
11
9
|
Parameter,
|
|
12
10
|
ParameterContainer,
|
|
11
|
+
ParameterGroup,
|
|
13
12
|
ParameterMode,
|
|
14
13
|
ParameterTypeBuiltin,
|
|
15
14
|
)
|
|
@@ -18,8 +17,6 @@ from griptape_nodes.exe_types.node_types import BaseNode, EndLoopNode, NodeResol
|
|
|
18
17
|
from griptape_nodes.exe_types.type_validator import TypeValidator
|
|
19
18
|
from griptape_nodes.node_library.library_registry import LibraryNameAndVersion, LibraryRegistry
|
|
20
19
|
from griptape_nodes.retained_mode.events.base_events import (
|
|
21
|
-
ExecutionEvent,
|
|
22
|
-
ExecutionGriptapeNodeEvent,
|
|
23
20
|
ResultPayload,
|
|
24
21
|
ResultPayloadFailure,
|
|
25
22
|
)
|
|
@@ -92,7 +89,6 @@ from griptape_nodes.retained_mode.events.parameter_events import (
|
|
|
92
89
|
AddParameterToNodeRequest,
|
|
93
90
|
AddParameterToNodeResultFailure,
|
|
94
91
|
AddParameterToNodeResultSuccess,
|
|
95
|
-
AlterElementEvent,
|
|
96
92
|
AlterParameterDetailsRequest,
|
|
97
93
|
AlterParameterDetailsResultFailure,
|
|
98
94
|
AlterParameterDetailsResultSuccess,
|
|
@@ -112,6 +108,9 @@ from griptape_nodes.retained_mode.events.parameter_events import (
|
|
|
112
108
|
RemoveParameterFromNodeRequest,
|
|
113
109
|
RemoveParameterFromNodeResultFailure,
|
|
114
110
|
RemoveParameterFromNodeResultSuccess,
|
|
111
|
+
RenameParameterRequest,
|
|
112
|
+
RenameParameterResultFailure,
|
|
113
|
+
RenameParameterResultSuccess,
|
|
115
114
|
SetParameterValueRequest,
|
|
116
115
|
SetParameterValueResultFailure,
|
|
117
116
|
SetParameterValueResultSuccess,
|
|
@@ -156,6 +155,7 @@ class NodeManager:
|
|
|
156
155
|
)
|
|
157
156
|
event_manager.assign_manager_to_request_type(GetParameterValueRequest, self.on_get_parameter_value_request)
|
|
158
157
|
event_manager.assign_manager_to_request_type(SetParameterValueRequest, self.on_set_parameter_value_request)
|
|
158
|
+
event_manager.assign_manager_to_request_type(RenameParameterRequest, self.on_rename_parameter_request)
|
|
159
159
|
event_manager.assign_manager_to_request_type(ResolveNodeRequest, self.on_resolve_from_node_request)
|
|
160
160
|
event_manager.assign_manager_to_request_type(GetAllNodeInfoRequest, self.on_get_all_node_info_request)
|
|
161
161
|
event_manager.assign_manager_to_request_type(
|
|
@@ -217,7 +217,7 @@ class NodeManager:
|
|
|
217
217
|
if parent_flow_name == old_name:
|
|
218
218
|
self._name_to_parent_flow_name[node_name] = new_name
|
|
219
219
|
|
|
220
|
-
def on_create_node_request(self, request: CreateNodeRequest) -> ResultPayload: # noqa: C901, PLR0912, PLR0915
|
|
220
|
+
def on_create_node_request(self, request: CreateNodeRequest) -> ResultPayload: # noqa: C901, PLR0911, PLR0912, PLR0915
|
|
221
221
|
# Validate as much as possible before we actually create one.
|
|
222
222
|
parent_flow_name = request.override_parent_flow_name
|
|
223
223
|
parent_flow = None
|
|
@@ -321,30 +321,53 @@ class NodeManager:
|
|
|
321
321
|
|
|
322
322
|
if isinstance(node, StartLoopNode) and not request.initial_setup:
|
|
323
323
|
# If it's StartLoop, create an EndLoop and connect it to the StartLoop.
|
|
324
|
+
# Get the class name of the node
|
|
325
|
+
node_class_name = node.__class__.__name__
|
|
326
|
+
|
|
327
|
+
# Get the opposing EndNode
|
|
328
|
+
# TODO: (griptape) Get paired classes implemented so we dont need to do name stuff. https://github.com/griptape-ai/griptape-nodes/issues/1549
|
|
329
|
+
end_class_name = node_class_name.replace("Start", "End")
|
|
330
|
+
|
|
331
|
+
# Check and see if the class exists
|
|
332
|
+
libraries_with_node_type = LibraryRegistry.get_libraries_with_node_type(end_class_name)
|
|
333
|
+
if not libraries_with_node_type:
|
|
334
|
+
msg = f"End class '{end_class_name}' does not exist for start class '{node_class_name}'"
|
|
335
|
+
logger.error(msg)
|
|
336
|
+
return CreateNodeResultFailure()
|
|
337
|
+
|
|
338
|
+
# Create the EndNode
|
|
324
339
|
end_loop = GriptapeNodes.handle_request(
|
|
325
340
|
CreateNodeRequest(
|
|
326
|
-
node_type=
|
|
341
|
+
node_type=end_class_name,
|
|
327
342
|
metadata={
|
|
328
343
|
"position": {"x": node.metadata["position"]["x"] + 650, "y": node.metadata["position"]["y"]}
|
|
329
344
|
},
|
|
330
345
|
override_parent_flow_name=parent_flow_name,
|
|
331
346
|
)
|
|
332
347
|
)
|
|
333
|
-
if isinstance(end_loop, CreateNodeResultSuccess):
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
348
|
+
if not isinstance(end_loop, CreateNodeResultSuccess):
|
|
349
|
+
msg = f"Failed to create EndLoop node for StartLoop node '{node.name}'"
|
|
350
|
+
logger.error(msg)
|
|
351
|
+
return CreateNodeResultFailure()
|
|
352
|
+
|
|
353
|
+
# Create Loop between output and input to the start node.
|
|
354
|
+
GriptapeNodes.handle_request(
|
|
355
|
+
CreateConnectionRequest(
|
|
356
|
+
source_node_name=node.name,
|
|
357
|
+
source_parameter_name="loop",
|
|
358
|
+
target_node_name=end_loop.node_name,
|
|
359
|
+
target_parameter_name="from_start",
|
|
342
360
|
)
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
361
|
+
)
|
|
362
|
+
end_node = self.get_node_by_name(end_loop.node_name)
|
|
363
|
+
if not isinstance(end_node, EndLoopNode):
|
|
364
|
+
msg = f"End node '{end_loop.node_name}' is not a valid EndLoopNode"
|
|
365
|
+
logger.error(msg)
|
|
366
|
+
return CreateNodeResultFailure()
|
|
367
|
+
|
|
368
|
+
# create the connection
|
|
369
|
+
node.end_node = end_node
|
|
370
|
+
end_node.start_node = node
|
|
348
371
|
|
|
349
372
|
return CreateNodeResultSuccess(
|
|
350
373
|
node_name=node.name, node_type=node.__class__.__name__, specific_library_name=request.specific_library_name
|
|
@@ -700,6 +723,24 @@ class NodeManager:
|
|
|
700
723
|
)
|
|
701
724
|
return result
|
|
702
725
|
|
|
726
|
+
def generate_unique_parameter_name(self, node: BaseNode, base_name: str) -> str:
|
|
727
|
+
"""Generate a unique parameter name for a node by appending a number if needed.
|
|
728
|
+
|
|
729
|
+
Args:
|
|
730
|
+
node: The node to check for existing parameter names
|
|
731
|
+
base_name: The desired base name for the parameter
|
|
732
|
+
|
|
733
|
+
Returns:
|
|
734
|
+
A unique parameter name that doesn't conflict with existing parameters
|
|
735
|
+
"""
|
|
736
|
+
if node.get_parameter_by_name(base_name) is None:
|
|
737
|
+
return base_name
|
|
738
|
+
|
|
739
|
+
counter = 1
|
|
740
|
+
while node.get_parameter_by_name(f"{base_name}_{counter}") is not None:
|
|
741
|
+
counter += 1
|
|
742
|
+
return f"{base_name}_{counter}"
|
|
743
|
+
|
|
703
744
|
def on_add_parameter_to_node_request(self, request: AddParameterToNodeRequest) -> ResultPayload: # noqa: C901, PLR0911, PLR0912, PLR0915
|
|
704
745
|
node_name = request.node_name
|
|
705
746
|
node = None
|
|
@@ -744,6 +785,7 @@ class NodeManager:
|
|
|
744
785
|
logger.exception(details)
|
|
745
786
|
result = AddParameterToNodeResultFailure()
|
|
746
787
|
return result
|
|
788
|
+
|
|
747
789
|
return AddParameterToNodeResultSuccess(
|
|
748
790
|
parameter_name=new_param.name, type=new_param.type, node_name=node_name
|
|
749
791
|
)
|
|
@@ -752,13 +794,14 @@ class NodeManager:
|
|
|
752
794
|
logger.error(details)
|
|
753
795
|
result = AddParameterToNodeResultFailure()
|
|
754
796
|
return result
|
|
755
|
-
# Does the Node already have a parameter by this name?
|
|
756
|
-
if node.get_parameter_by_name(request.parameter_name) is not None:
|
|
757
|
-
details = f"Attempted to add Parameter '{request.parameter_name}' to Node '{node_name}'. Failed because it already had a Parameter with that name on it. Parameter names must be unique within the Node."
|
|
758
|
-
logger.error(details)
|
|
759
797
|
|
|
760
|
-
|
|
761
|
-
|
|
798
|
+
# Generate a unique parameter name if needed
|
|
799
|
+
requested_parameter_name = request.parameter_name
|
|
800
|
+
if requested_parameter_name is None:
|
|
801
|
+
# Not allowed to have a parameter with no name, so we'll give it a default name
|
|
802
|
+
requested_parameter_name = "parameter"
|
|
803
|
+
|
|
804
|
+
final_param_name = self.generate_unique_parameter_name(node, requested_parameter_name)
|
|
762
805
|
|
|
763
806
|
# Let's see if the Parameter is properly formed.
|
|
764
807
|
# If a Parameter is intended for Control, it needs to have that be the exclusive type.
|
|
@@ -799,7 +842,7 @@ class NodeManager:
|
|
|
799
842
|
|
|
800
843
|
# Let's roll, I guess.
|
|
801
844
|
new_param = Parameter(
|
|
802
|
-
name=
|
|
845
|
+
name=final_param_name,
|
|
803
846
|
type=request.type,
|
|
804
847
|
input_types=request.input_types,
|
|
805
848
|
output_type=request.output_type,
|
|
@@ -822,12 +865,17 @@ class NodeManager:
|
|
|
822
865
|
logger.info(new_param.name)
|
|
823
866
|
node.add_parameter(new_param)
|
|
824
867
|
except Exception as e:
|
|
825
|
-
details = f"Couldn't add parameter with name {request.parameter_name} to
|
|
868
|
+
details = f"Couldn't add parameter with name {request.parameter_name} to Node '{node_name}'. Error: {e}"
|
|
826
869
|
logger.error(details)
|
|
827
870
|
return AddParameterToNodeResultFailure()
|
|
828
871
|
|
|
829
|
-
details = f"Successfully added Parameter '{
|
|
830
|
-
|
|
872
|
+
details = f"Successfully added Parameter '{final_param_name}' to Node '{node_name}'."
|
|
873
|
+
log_level = logging.DEBUG
|
|
874
|
+
if final_param_name != requested_parameter_name:
|
|
875
|
+
log_level = logging.WARNING
|
|
876
|
+
details = f"{details} WARNING: Had to rename from original parameter name '{requested_parameter_name}' as a parameter with this name already existed in node '{node_name}'."
|
|
877
|
+
|
|
878
|
+
logger.log(level=log_level, msg=details)
|
|
831
879
|
|
|
832
880
|
result = AddParameterToNodeResultSuccess(
|
|
833
881
|
parameter_name=new_param.name, type=new_param.type, node_name=node_name
|
|
@@ -861,83 +909,87 @@ class NodeManager:
|
|
|
861
909
|
result = RemoveParameterFromNodeResultFailure()
|
|
862
910
|
return result
|
|
863
911
|
|
|
864
|
-
# Does the
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
details = f"Attempted to remove Parameter '{request.parameter_name}' from Node '{node_name}'. Failed because it didn't have a Parameter with that name on it."
|
|
912
|
+
# Does the Element actually exist on the Node?
|
|
913
|
+
element = node.get_element_by_name_and_type(request.parameter_name)
|
|
914
|
+
if element is None:
|
|
915
|
+
details = f"Attempted to remove Element '{request.parameter_name}' from Node '{node_name}'. Failed because it didn't have an Element with that name on it."
|
|
869
916
|
logger.error(details)
|
|
870
917
|
|
|
871
918
|
result = RemoveParameterFromNodeResultFailure()
|
|
872
919
|
return result
|
|
873
|
-
|
|
874
|
-
|
|
920
|
+
|
|
921
|
+
# If it's a ParameterGroup, we need to remove all the Parameters inside it.
|
|
922
|
+
if isinstance(element, ParameterGroup):
|
|
923
|
+
for child in element.find_elements_by_type(Parameter):
|
|
875
924
|
GriptapeNodes.handle_request(RemoveParameterFromNodeRequest(child.name, node_name))
|
|
876
925
|
node.remove_parameter_element_by_name(request.parameter_name)
|
|
926
|
+
|
|
877
927
|
return RemoveParameterFromNodeResultSuccess()
|
|
878
928
|
|
|
879
929
|
# No tricky stuff, users!
|
|
880
|
-
if
|
|
881
|
-
|
|
930
|
+
# if user_defined doesn't exist, or is false, then it's not user-defined
|
|
931
|
+
if not getattr(element, "user_defined", False):
|
|
932
|
+
details = f"Attempted to remove Element '{request.parameter_name}' from Node '{node_name}'. Failed because the Element was not user-defined (i.e., critical to the Node implementation). Only user-defined Elements can be removed from a Node."
|
|
882
933
|
logger.error(details)
|
|
883
934
|
|
|
884
935
|
result = RemoveParameterFromNodeResultFailure()
|
|
885
936
|
return result
|
|
886
937
|
|
|
887
938
|
# Get all the connections to/from this Parameter.
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
939
|
+
if isinstance(element, Parameter):
|
|
940
|
+
list_node_connections_request = ListConnectionsForNodeRequest(node_name=node_name)
|
|
941
|
+
list_connections_result = GriptapeNodes.handle_request(request=list_node_connections_request)
|
|
942
|
+
if not isinstance(list_connections_result, ListConnectionsForNodeResultSuccess):
|
|
943
|
+
details = f"Attempted to remove Parameter '{request.parameter_name}' from Node '{node_name}'. Failed because we were unable to get a list of Connections for the Parameter's Node."
|
|
944
|
+
logger.error(details)
|
|
893
945
|
|
|
894
|
-
|
|
895
|
-
|
|
946
|
+
result = RemoveParameterFromNodeResultFailure()
|
|
947
|
+
return result
|
|
896
948
|
|
|
897
|
-
|
|
949
|
+
# We have a list of all connections to the NODE. Sift down to just those that are about this PARAMETER.
|
|
898
950
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
951
|
+
# Destroy all the incoming Connections to this PARAMETER
|
|
952
|
+
for incoming_connection in list_connections_result.incoming_connections:
|
|
953
|
+
if incoming_connection.target_parameter_name == request.parameter_name:
|
|
954
|
+
delete_request = DeleteConnectionRequest(
|
|
955
|
+
source_node_name=incoming_connection.source_node_name,
|
|
956
|
+
source_parameter_name=incoming_connection.source_parameter_name,
|
|
957
|
+
target_node_name=node_name,
|
|
958
|
+
target_parameter_name=incoming_connection.target_parameter_name,
|
|
959
|
+
)
|
|
960
|
+
delete_result = GriptapeNodes.handle_request(delete_request)
|
|
961
|
+
if isinstance(delete_result, DeleteConnectionResultFailure):
|
|
962
|
+
details = f"Attempted to remove Parameter '{request.parameter_name}' from Node '{node_name}'. Failed because we were unable to delete a Connection for that Parameter."
|
|
963
|
+
logger.error(details)
|
|
912
964
|
|
|
913
|
-
|
|
965
|
+
result = RemoveParameterFromNodeResultFailure()
|
|
914
966
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
967
|
+
# Destroy all the outgoing Connections from this PARAMETER
|
|
968
|
+
for outgoing_connection in list_connections_result.outgoing_connections:
|
|
969
|
+
if outgoing_connection.source_parameter_name == request.parameter_name:
|
|
970
|
+
delete_request = DeleteConnectionRequest(
|
|
971
|
+
source_node_name=node_name,
|
|
972
|
+
source_parameter_name=outgoing_connection.source_parameter_name,
|
|
973
|
+
target_node_name=outgoing_connection.target_node_name,
|
|
974
|
+
target_parameter_name=outgoing_connection.target_parameter_name,
|
|
975
|
+
)
|
|
976
|
+
delete_result = GriptapeNodes.handle_request(delete_request)
|
|
977
|
+
if isinstance(delete_result, DeleteConnectionResultFailure):
|
|
978
|
+
details = f"Attempted to remove Parameter '{request.parameter_name}' from Node '{node_name}'. Failed because we were unable to delete a Connection for that Parameter."
|
|
979
|
+
logger.error(details)
|
|
928
980
|
|
|
929
|
-
|
|
981
|
+
result = RemoveParameterFromNodeResultFailure()
|
|
930
982
|
|
|
931
|
-
# Delete the
|
|
932
|
-
if
|
|
933
|
-
node.remove_parameter_element(
|
|
983
|
+
# Delete the Element itself.
|
|
984
|
+
if element is not None:
|
|
985
|
+
node.remove_parameter_element(element)
|
|
934
986
|
else:
|
|
935
|
-
details = f"Attempted to remove
|
|
987
|
+
details = f"Attempted to remove Element '{request.parameter_name}' from Node '{node_name}'. Failed because element didn't exist."
|
|
936
988
|
logger.error(details)
|
|
937
989
|
|
|
938
990
|
result = RemoveParameterFromNodeResultFailure()
|
|
939
991
|
|
|
940
|
-
details = f"Successfully removed
|
|
992
|
+
details = f"Successfully removed Element '{request.parameter_name}' from Node '{node_name}'."
|
|
941
993
|
logger.debug(details)
|
|
942
994
|
|
|
943
995
|
result = RemoveParameterFromNodeResultSuccess()
|
|
@@ -968,39 +1020,43 @@ class NodeManager:
|
|
|
968
1020
|
result = GetParameterDetailsResultFailure()
|
|
969
1021
|
return result
|
|
970
1022
|
|
|
971
|
-
# Does the
|
|
972
|
-
|
|
973
|
-
if parameter is None:
|
|
974
|
-
details = f"Attempted to get details for Parameter '{request.parameter_name}' from Node '{node_name}'. Failed because it didn't have a Parameter with that name on it."
|
|
975
|
-
logger.error(details)
|
|
1023
|
+
# Does the Element actually exist on the Node?
|
|
1024
|
+
element = node.get_element_by_name_and_type(request.parameter_name)
|
|
976
1025
|
|
|
977
|
-
|
|
978
|
-
|
|
1026
|
+
if element is None:
|
|
1027
|
+
details = f"Attempted to get details for Element '{request.parameter_name}' from Node '{node_name}'. Failed because it didn't have an Element with that name on it."
|
|
1028
|
+
logger.error(details)
|
|
1029
|
+
return GetParameterDetailsResultFailure()
|
|
979
1030
|
|
|
980
1031
|
# Let's bundle up the details.
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
allows_output = ParameterMode.OUTPUT in modes_allowed
|
|
1032
|
+
allows_input = False
|
|
1033
|
+
allows_property = False
|
|
1034
|
+
allows_output = False
|
|
985
1035
|
|
|
986
|
-
|
|
987
|
-
|
|
1036
|
+
if isinstance(element, Parameter):
|
|
1037
|
+
modes_allowed = element.allowed_modes
|
|
1038
|
+
allows_input = ParameterMode.INPUT in modes_allowed
|
|
1039
|
+
allows_property = ParameterMode.PROPERTY in modes_allowed
|
|
1040
|
+
allows_output = ParameterMode.OUTPUT in modes_allowed
|
|
1041
|
+
|
|
1042
|
+
details = f"Successfully got details for Element '{request.parameter_name}' from Node '{node_name}'."
|
|
1043
|
+
logger.debug(details)
|
|
988
1044
|
|
|
989
1045
|
result = GetParameterDetailsResultSuccess(
|
|
990
|
-
element_id=
|
|
991
|
-
type=
|
|
992
|
-
input_types=
|
|
993
|
-
output_type=
|
|
994
|
-
default_value=
|
|
995
|
-
tooltip=
|
|
996
|
-
tooltip_as_input=
|
|
997
|
-
tooltip_as_property=
|
|
998
|
-
tooltip_as_output=
|
|
1046
|
+
element_id=element.element_id,
|
|
1047
|
+
type=getattr(element, "type", ""),
|
|
1048
|
+
input_types=getattr(element, "input_types", []),
|
|
1049
|
+
output_type=getattr(element, "output_type", ""),
|
|
1050
|
+
default_value=getattr(element, "default_value", None),
|
|
1051
|
+
tooltip=getattr(element, "tooltip", ""),
|
|
1052
|
+
tooltip_as_input=getattr(element, "tooltip_as_input", None),
|
|
1053
|
+
tooltip_as_property=getattr(element, "tooltip_as_property", None),
|
|
1054
|
+
tooltip_as_output=getattr(element, "tooltip_as_output", None),
|
|
999
1055
|
mode_allowed_input=allows_input,
|
|
1000
1056
|
mode_allowed_property=allows_property,
|
|
1001
1057
|
mode_allowed_output=allows_output,
|
|
1002
|
-
is_user_defined=
|
|
1003
|
-
ui_options=
|
|
1058
|
+
is_user_defined=getattr(element, "user_defined", False),
|
|
1059
|
+
ui_options=getattr(element, "ui_options", None),
|
|
1004
1060
|
)
|
|
1005
1061
|
return result
|
|
1006
1062
|
|
|
@@ -1040,7 +1096,7 @@ class NodeManager:
|
|
|
1040
1096
|
return GetNodeElementDetailsResultFailure()
|
|
1041
1097
|
|
|
1042
1098
|
element_details = element.to_dict()
|
|
1043
|
-
# We need to get
|
|
1099
|
+
# We need to get element values from here
|
|
1044
1100
|
param_to_value = {}
|
|
1045
1101
|
self._set_param_to_value(node, element, param_to_value)
|
|
1046
1102
|
if param_to_value:
|
|
@@ -1076,17 +1132,18 @@ class NodeManager:
|
|
|
1076
1132
|
# Otherwise, just set it here. It'll be handled in .json() when we send it over.
|
|
1077
1133
|
param_to_value[element_id] = value
|
|
1078
1134
|
|
|
1079
|
-
def modify_alterable_fields(self, request: AlterParameterDetailsRequest, parameter:
|
|
1080
|
-
if
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1135
|
+
def modify_alterable_fields(self, request: AlterParameterDetailsRequest, parameter: BaseNodeElement) -> None:
|
|
1136
|
+
if isinstance(parameter, Parameter):
|
|
1137
|
+
if request.tooltip:
|
|
1138
|
+
parameter.tooltip = request.tooltip
|
|
1139
|
+
if request.tooltip_as_input is not None:
|
|
1140
|
+
parameter.tooltip_as_input = request.tooltip_as_input
|
|
1141
|
+
if request.tooltip_as_property is not None:
|
|
1142
|
+
parameter.tooltip_as_property = request.tooltip_as_property
|
|
1143
|
+
if request.tooltip_as_output is not None:
|
|
1144
|
+
parameter.tooltip_as_output = request.tooltip_as_output
|
|
1145
|
+
if request.ui_options is not None and hasattr(parameter, "ui_options"):
|
|
1146
|
+
parameter.ui_options = request.ui_options # type: ignore[attr-defined]
|
|
1090
1147
|
|
|
1091
1148
|
def modify_key_parameter_fields(self, request: AlterParameterDetailsRequest, parameter: Parameter) -> None:
|
|
1092
1149
|
if request.type is not None:
|
|
@@ -1114,7 +1171,67 @@ class NodeManager:
|
|
|
1114
1171
|
else:
|
|
1115
1172
|
parameter.allowed_modes.discard(ParameterMode.OUTPUT)
|
|
1116
1173
|
|
|
1117
|
-
def
|
|
1174
|
+
def _validate_and_break_invalid_connections(
|
|
1175
|
+
self, node_name: str, parameter: Parameter, request: AlterParameterDetailsRequest
|
|
1176
|
+
) -> ResultPayload | None:
|
|
1177
|
+
"""Validate and break any connections that are no longer valid after a parameter type change.
|
|
1178
|
+
|
|
1179
|
+
This method checks both incoming and outgoing connections for a parameter and removes
|
|
1180
|
+
any that are no longer type-compatible after the parameter's type has been changed.
|
|
1181
|
+
|
|
1182
|
+
Returns:
|
|
1183
|
+
ResultPayload | None: Returns AlterParameterDetailsResultFailure if any connection deletion fails,
|
|
1184
|
+
None otherwise.
|
|
1185
|
+
"""
|
|
1186
|
+
# Get all connections for this node
|
|
1187
|
+
list_connections_request = ListConnectionsForNodeRequest(node_name=node_name)
|
|
1188
|
+
list_connections_result = self.on_list_connections_for_node_request(list_connections_request)
|
|
1189
|
+
|
|
1190
|
+
if not isinstance(list_connections_result, ListConnectionsForNodeResultSuccess):
|
|
1191
|
+
# No connections exist for this node, which is not a failure - just nothing to validate
|
|
1192
|
+
return None
|
|
1193
|
+
|
|
1194
|
+
# Check and break invalid incoming connections
|
|
1195
|
+
for conn in list_connections_result.incoming_connections:
|
|
1196
|
+
if conn.target_parameter_name == request.parameter_name:
|
|
1197
|
+
source_node = self.get_node_by_name(conn.source_node_name)
|
|
1198
|
+
source_param = source_node.get_parameter_by_name(conn.source_parameter_name)
|
|
1199
|
+
if source_param and not parameter.is_incoming_type_allowed(source_param.output_type):
|
|
1200
|
+
delete_result = GriptapeNodes.FlowManager().on_delete_connection_request(
|
|
1201
|
+
DeleteConnectionRequest(
|
|
1202
|
+
source_node_name=conn.source_node_name,
|
|
1203
|
+
source_parameter_name=conn.source_parameter_name,
|
|
1204
|
+
target_node_name=node_name,
|
|
1205
|
+
target_parameter_name=request.parameter_name,
|
|
1206
|
+
)
|
|
1207
|
+
)
|
|
1208
|
+
if isinstance(delete_result, ResultPayloadFailure):
|
|
1209
|
+
details = f"Failed to delete incompatible incoming connection from {conn.source_node_name}.{conn.source_parameter_name} to {node_name}.{request.parameter_name}: {delete_result}"
|
|
1210
|
+
logger.error(details)
|
|
1211
|
+
return AlterParameterDetailsResultFailure()
|
|
1212
|
+
|
|
1213
|
+
# Check and break invalid outgoing connections
|
|
1214
|
+
for conn in list_connections_result.outgoing_connections:
|
|
1215
|
+
if conn.source_parameter_name == request.parameter_name:
|
|
1216
|
+
target_node = self.get_node_by_name(conn.target_node_name)
|
|
1217
|
+
target_param = target_node.get_parameter_by_name(conn.target_parameter_name)
|
|
1218
|
+
if target_param and not target_param.is_incoming_type_allowed(parameter.output_type):
|
|
1219
|
+
delete_result = GriptapeNodes.FlowManager().on_delete_connection_request(
|
|
1220
|
+
DeleteConnectionRequest(
|
|
1221
|
+
source_node_name=node_name,
|
|
1222
|
+
source_parameter_name=request.parameter_name,
|
|
1223
|
+
target_node_name=conn.target_node_name,
|
|
1224
|
+
target_parameter_name=conn.target_parameter_name,
|
|
1225
|
+
)
|
|
1226
|
+
)
|
|
1227
|
+
if isinstance(delete_result, ResultPayloadFailure):
|
|
1228
|
+
details = f"Failed to delete incompatible outgoing connection from {node_name}.{request.parameter_name} to {conn.target_node_name}.{conn.target_parameter_name}: {delete_result}"
|
|
1229
|
+
logger.error(details)
|
|
1230
|
+
return AlterParameterDetailsResultFailure()
|
|
1231
|
+
|
|
1232
|
+
return None
|
|
1233
|
+
|
|
1234
|
+
def on_alter_parameter_details_request(self, request: AlterParameterDetailsRequest) -> ResultPayload: # noqa: C901
|
|
1118
1235
|
node_name = request.node_name
|
|
1119
1236
|
node = None
|
|
1120
1237
|
|
|
@@ -1137,36 +1254,42 @@ class NodeManager:
|
|
|
1137
1254
|
|
|
1138
1255
|
return AlterParameterDetailsResultFailure()
|
|
1139
1256
|
|
|
1140
|
-
# Does the
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1257
|
+
# Does the Element actually exist on the Node?
|
|
1258
|
+
element = node.get_element_by_name_and_type(request.parameter_name)
|
|
1259
|
+
if element is None:
|
|
1260
|
+
details = f"Attempted to alter details for Element '{request.parameter_name}' from Node '{node_name}'. Failed because it didn't have an Element with that name on it."
|
|
1261
|
+
logger.error(details)
|
|
1262
|
+
return AlterParameterDetailsResultFailure()
|
|
1263
|
+
if request.ui_options is not None:
|
|
1264
|
+
element.ui_options = request.ui_options # type: ignore[attr-defined]
|
|
1265
|
+
|
|
1266
|
+
# Check and handle connections if type was changed
|
|
1267
|
+
if isinstance(element, Parameter) and (
|
|
1268
|
+
request.type is not None or request.input_types is not None or request.output_type is not None
|
|
1269
|
+
):
|
|
1270
|
+
result = self._validate_and_break_invalid_connections(node_name, element, request)
|
|
1271
|
+
if isinstance(result, AlterParameterDetailsResultFailure):
|
|
1272
|
+
return result
|
|
1153
1273
|
|
|
1154
1274
|
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/827
|
|
1155
|
-
# Now change all the values on the
|
|
1156
|
-
self.modify_alterable_fields(request,
|
|
1275
|
+
# Now change all the values on the Element.
|
|
1276
|
+
self.modify_alterable_fields(request, element)
|
|
1277
|
+
|
|
1157
1278
|
# The rest of these are not alterable
|
|
1158
|
-
if
|
|
1159
|
-
#
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1279
|
+
if isinstance(element, Parameter):
|
|
1280
|
+
if hasattr(element, "user_defined") and element.user_defined is False and request.request_id: # type: ignore[attr-defined]
|
|
1281
|
+
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/826
|
|
1282
|
+
details = f"Attempted to alter details for Element '{request.parameter_name}' from Node '{node_name}'. Could only alter some values because the Element was not user-defined (i.e., critical to the Node implementation). Only user-defined Elements can be totally modified from a Node."
|
|
1283
|
+
logger.warning(details)
|
|
1284
|
+
return AlterParameterDetailsResultSuccess()
|
|
1285
|
+
self.modify_key_parameter_fields(request, element)
|
|
1286
|
+
|
|
1164
1287
|
# This field requires the node as well
|
|
1165
1288
|
if request.default_value is not None:
|
|
1166
1289
|
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/825
|
|
1167
1290
|
node.parameter_values[request.parameter_name] = request.default_value
|
|
1168
1291
|
|
|
1169
|
-
details = f"Successfully altered details for
|
|
1292
|
+
details = f"Successfully altered details for Element '{request.parameter_name}' from Node '{node_name}'."
|
|
1170
1293
|
logger.debug(details)
|
|
1171
1294
|
|
|
1172
1295
|
result = AlterParameterDetailsResultSuccess()
|
|
@@ -1355,18 +1478,12 @@ class NodeManager:
|
|
|
1355
1478
|
return NodeManager.ModifiedReturnValue(object_created, modified)
|
|
1356
1479
|
# Otherwise use set_parameter_value. This calls our converters and validators.
|
|
1357
1480
|
old_value = node.get_parameter_value(request.parameter_name)
|
|
1358
|
-
|
|
1481
|
+
node.set_parameter_value(request.parameter_name, object_created)
|
|
1359
1482
|
# Get the "converted" value here.
|
|
1360
1483
|
finalized_value = node.get_parameter_value(request.parameter_name)
|
|
1361
1484
|
if old_value != finalized_value:
|
|
1362
1485
|
modified = True
|
|
1363
1486
|
# If any parameters were dependent on that value, we're calling this details request to emit the result to the editor.
|
|
1364
|
-
if modified_parameters:
|
|
1365
|
-
for modified_parameter_name in modified_parameters:
|
|
1366
|
-
modified_parameter = node.root_ui_element.find_element_by_name(modified_parameter_name)
|
|
1367
|
-
if modified_parameter is not None:
|
|
1368
|
-
modified_request = AlterElementEvent(element_details=modified_parameter.to_event(node))
|
|
1369
|
-
EventBus.publish_event(ExecutionGriptapeNodeEvent(ExecutionEvent(payload=modified_request)))
|
|
1370
1487
|
return NodeManager.ModifiedReturnValue(finalized_value, modified)
|
|
1371
1488
|
|
|
1372
1489
|
# For C901 (too complex): Need to give customers explicit reasons for failure on each case.
|
|
@@ -2255,3 +2372,83 @@ class NodeManager:
|
|
|
2255
2372
|
else:
|
|
2256
2373
|
commands.append(output_command)
|
|
2257
2374
|
return commands if commands else None
|
|
2375
|
+
|
|
2376
|
+
def on_rename_parameter_request(self, request: RenameParameterRequest) -> ResultPayload: # noqa: C901, PLR0912
|
|
2377
|
+
"""Handle renaming a parameter on a node.
|
|
2378
|
+
|
|
2379
|
+
Args:
|
|
2380
|
+
request: The rename parameter request containing the old and new parameter names
|
|
2381
|
+
|
|
2382
|
+
Returns:
|
|
2383
|
+
ResultPayload: Success or failure result
|
|
2384
|
+
"""
|
|
2385
|
+
# Get the node
|
|
2386
|
+
node_name = request.node_name
|
|
2387
|
+
if node_name is None:
|
|
2388
|
+
if not GriptapeNodes.ContextManager().has_current_node():
|
|
2389
|
+
details = "Attempted to rename Parameter in the Current Context. Failed because the Current Context was empty."
|
|
2390
|
+
logger.error(details)
|
|
2391
|
+
return RenameParameterResultFailure()
|
|
2392
|
+
node = GriptapeNodes.ContextManager().get_current_node()
|
|
2393
|
+
node_name = node.name
|
|
2394
|
+
else:
|
|
2395
|
+
try:
|
|
2396
|
+
node = self.get_node_by_name(node_name)
|
|
2397
|
+
except KeyError as err:
|
|
2398
|
+
details = f"Attempted to rename Parameter '{request.parameter_name}' on Node '{node_name}'. Failed because the Node could not be found. Error: {err}"
|
|
2399
|
+
logger.error(details)
|
|
2400
|
+
return RenameParameterResultFailure()
|
|
2401
|
+
|
|
2402
|
+
# Get the parameter
|
|
2403
|
+
parameter = node.get_parameter_by_name(request.parameter_name)
|
|
2404
|
+
if parameter is None:
|
|
2405
|
+
details = f"Attempted to rename Parameter '{request.parameter_name}' on Node '{node_name}'. Failed because the Parameter could not be found."
|
|
2406
|
+
logger.error(details)
|
|
2407
|
+
return RenameParameterResultFailure()
|
|
2408
|
+
|
|
2409
|
+
# Validate the new parameter name
|
|
2410
|
+
if any(char.isspace() for char in request.new_parameter_name):
|
|
2411
|
+
details = f"Failed to rename Parameter '{request.parameter_name}' to '{request.new_parameter_name}'. Parameter names cannot contain any whitespace characters."
|
|
2412
|
+
logger.error(details)
|
|
2413
|
+
return RenameParameterResultFailure()
|
|
2414
|
+
|
|
2415
|
+
# Check for duplicate names
|
|
2416
|
+
if node.does_name_exist(request.new_parameter_name):
|
|
2417
|
+
details = f"Failed to rename Parameter '{request.parameter_name}' to '{request.new_parameter_name}'. A Parameter with that name already exists."
|
|
2418
|
+
logger.error(details)
|
|
2419
|
+
return RenameParameterResultFailure()
|
|
2420
|
+
|
|
2421
|
+
# Get all connections for this node
|
|
2422
|
+
flow_name = self.get_node_parent_flow_by_name(node_name)
|
|
2423
|
+
flow = GriptapeNodes.FlowManager().get_flow_by_name(flow_name)
|
|
2424
|
+
|
|
2425
|
+
# Update connections that reference this parameter
|
|
2426
|
+
if node_name in flow.connections.incoming_index:
|
|
2427
|
+
incoming_connections = flow.connections.incoming_index[node_name]
|
|
2428
|
+
for connection_ids in incoming_connections.values():
|
|
2429
|
+
for connection_id in connection_ids:
|
|
2430
|
+
connection = flow.connections.connections[connection_id]
|
|
2431
|
+
if connection.target_parameter.name == request.parameter_name:
|
|
2432
|
+
connection.target_parameter.name = request.new_parameter_name
|
|
2433
|
+
|
|
2434
|
+
if node_name in flow.connections.outgoing_index:
|
|
2435
|
+
outgoing_connections = flow.connections.outgoing_index[node_name]
|
|
2436
|
+
for connection_ids in outgoing_connections.values():
|
|
2437
|
+
for connection_id in connection_ids:
|
|
2438
|
+
connection = flow.connections.connections[connection_id]
|
|
2439
|
+
if connection.source_parameter.name == request.parameter_name:
|
|
2440
|
+
connection.source_parameter.name = request.new_parameter_name
|
|
2441
|
+
|
|
2442
|
+
# Update parameter name
|
|
2443
|
+
old_name = parameter.name
|
|
2444
|
+
parameter.name = request.new_parameter_name
|
|
2445
|
+
|
|
2446
|
+
# Update parameter values if they exist
|
|
2447
|
+
if old_name in node.parameter_values:
|
|
2448
|
+
node.parameter_values[request.new_parameter_name] = node.parameter_values.pop(old_name)
|
|
2449
|
+
if old_name in node.parameter_output_values:
|
|
2450
|
+
node.parameter_output_values[request.new_parameter_name] = node.parameter_output_values.pop(old_name)
|
|
2451
|
+
|
|
2452
|
+
return RenameParameterResultSuccess(
|
|
2453
|
+
old_parameter_name=old_name, new_parameter_name=request.new_parameter_name, node_name=node_name
|
|
2454
|
+
)
|