griptape-nodes 0.50.0__tar.gz → 0.51.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/PKG-INFO +1 -1
  2. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/pyproject.toml +1 -1
  3. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/exe_types/node_types.py +2 -2
  4. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/machines/node_resolution.py +15 -8
  5. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/node_events.py +44 -0
  6. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/flow_manager.py +31 -7
  7. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/node_manager.py +58 -7
  8. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/README.md +0 -0
  9. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/__init__.py +0 -0
  10. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/app/.python-version +0 -0
  11. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/app/__init__.py +0 -0
  12. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/app/api.py +0 -0
  13. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/app/app.py +0 -0
  14. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/app/watch.py +0 -0
  15. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/bootstrap/__init__.py +0 -0
  16. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/bootstrap/workflow_executors/__init__.py +0 -0
  17. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +0 -0
  18. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/bootstrap/workflow_executors/subprocess_workflow_executor.py +0 -0
  19. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/bootstrap/workflow_executors/workflow_executor.py +0 -0
  20. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/drivers/__init__.py +0 -0
  21. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/drivers/storage/__init__.py +0 -0
  22. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/drivers/storage/base_storage_driver.py +0 -0
  23. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +0 -0
  24. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/drivers/storage/local_storage_driver.py +0 -0
  25. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/drivers/storage/storage_backend.py +0 -0
  26. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/exe_types/__init__.py +0 -0
  27. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/exe_types/connections.py +0 -0
  28. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/exe_types/core_types.py +0 -0
  29. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/exe_types/flow.py +0 -0
  30. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/exe_types/type_validator.py +0 -0
  31. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/machines/__init__.py +0 -0
  32. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/machines/control_flow.py +0 -0
  33. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/machines/fsm.py +0 -0
  34. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/mcp_server/__init__.py +0 -0
  35. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/mcp_server/server.py +0 -0
  36. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/mcp_server/ws_request_manager.py +0 -0
  37. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/node_library/__init__.py +0 -0
  38. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/node_library/advanced_node_library.py +0 -0
  39. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/node_library/library_registry.py +0 -0
  40. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/node_library/workflow_registry.py +0 -0
  41. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/py.typed +0 -0
  42. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/__init__.py +0 -0
  43. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/__init__.py +0 -0
  44. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/agent_events.py +0 -0
  45. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/app_events.py +0 -0
  46. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/arbitrary_python_events.py +0 -0
  47. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/base_events.py +0 -0
  48. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/config_events.py +0 -0
  49. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/connection_events.py +0 -0
  50. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/context_events.py +0 -0
  51. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/execution_events.py +0 -0
  52. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/flow_events.py +0 -0
  53. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/generate_request_payload_schemas.py +0 -0
  54. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/library_events.py +0 -0
  55. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/logger_events.py +0 -0
  56. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/object_events.py +0 -0
  57. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/os_events.py +0 -0
  58. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/parameter_events.py +0 -0
  59. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/payload_registry.py +0 -0
  60. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/secrets_events.py +0 -0
  61. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/static_file_events.py +0 -0
  62. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/sync_events.py +0 -0
  63. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/validation_events.py +0 -0
  64. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/events/workflow_events.py +0 -0
  65. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/griptape_nodes.py +0 -0
  66. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/__init__.py +0 -0
  67. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/agent_manager.py +0 -0
  68. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +0 -0
  69. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/config_manager.py +0 -0
  70. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/context_manager.py +0 -0
  71. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/engine_identity_manager.py +0 -0
  72. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/event_manager.py +0 -0
  73. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/__init__.py +0 -0
  74. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/data_models.py +0 -0
  75. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +0 -0
  76. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_fsm.py +0 -0
  77. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/__init__.py +0 -0
  78. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/base.py +0 -0
  79. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/github.py +0 -0
  80. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +0 -0
  81. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/package.py +0 -0
  82. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/sandbox.py +0 -0
  83. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance.py +0 -0
  84. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_status.py +0 -0
  85. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/library_manager.py +0 -0
  86. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/object_manager.py +0 -0
  87. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/operation_manager.py +0 -0
  88. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/os_manager.py +0 -0
  89. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/secrets_manager.py +0 -0
  90. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/session_manager.py +0 -0
  91. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/settings.py +0 -0
  92. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/static_files_manager.py +0 -0
  93. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/sync_manager.py +0 -0
  94. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/version_compatibility_manager.py +0 -0
  95. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/managers/workflow_manager.py +0 -0
  96. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/retained_mode.py +0 -0
  97. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/utils/__init__.py +0 -0
  98. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/utils/engine_identity.py +0 -0
  99. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/retained_mode/utils/name_generator.py +0 -0
  100. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/__init__.py +0 -0
  101. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/add_param_button.py +0 -0
  102. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/button.py +0 -0
  103. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/clamp.py +0 -0
  104. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/compare.py +0 -0
  105. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/compare_images.py +0 -0
  106. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/file_system_picker.py +0 -0
  107. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/minmax.py +0 -0
  108. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/options.py +0 -0
  109. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/slider.py +0 -0
  110. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/trait_registry.py +0 -0
  111. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/traits/traits.json +0 -0
  112. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/updater/__init__.py +0 -0
  113. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/updater/__main__.py +0 -0
  114. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/utils/__init__.py +0 -0
  115. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/utils/dict_utils.py +0 -0
  116. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/utils/image_preview.py +0 -0
  117. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/utils/metaclasses.py +0 -0
  118. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/utils/uv_utils.py +0 -0
  119. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/utils/version_utils.py +0 -0
  120. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/version_compatibility/__init__.py +0 -0
  121. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/version_compatibility/versions/__init__.py +0 -0
  122. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/version_compatibility/versions/v0_39_0/__init__.py +0 -0
  123. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +0 -0
  124. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/version_compatibility/workflow_versions/__init__.py +0 -0
  125. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/version_compatibility/workflow_versions/v0_7_0/__init__.py +0 -0
  126. {griptape_nodes-0.50.0 → griptape_nodes-0.51.1}/src/griptape_nodes/version_compatibility/workflow_versions/v0_7_0/local_executor_argument_addition.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: griptape-nodes
3
- Version: 0.50.0
3
+ Version: 0.51.1
4
4
  Summary: Add your description here
5
5
  Requires-Dist: griptape>=1.8.0
6
6
  Requires-Dist: pydantic>=2.10.6
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "griptape-nodes"
3
- version = "0.50.0"
3
+ version = "0.51.1"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12.0, <3.13"
@@ -1175,8 +1175,8 @@ class ErrorProxyNode(BaseNode):
1175
1175
  f"\nfrom the '{self.original_library_name}' library."
1176
1176
  f"\nIt encountered a problem when loading."
1177
1177
  f"\nThe technical issue:\n{self.failure_reason}\n\n"
1178
- f"Your original node will be restored once the issue above is fixed"
1179
- f"(which may require registering the appropriate library, or getting"
1178
+ f"Your original node will be restored once the issue above is fixed "
1179
+ f"(which may require registering the appropriate library, or getting "
1180
1180
  f"a code fix from the node author)."
1181
1181
  )
1182
1182
 
@@ -9,7 +9,7 @@ from typing import Any
9
9
  from griptape.events import EventBus
10
10
  from griptape.utils import with_contextvars
11
11
 
12
- from griptape_nodes.exe_types.core_types import ParameterTypeBuiltin
12
+ from griptape_nodes.exe_types.core_types import ParameterType, ParameterTypeBuiltin
13
13
  from griptape_nodes.exe_types.node_types import BaseNode, NodeResolutionState
14
14
  from griptape_nodes.exe_types.type_validator import TypeValidator
15
15
  from griptape_nodes.machines.fsm import FSM, State
@@ -229,14 +229,21 @@ class ExecuteNodeState(State):
229
229
  output_value = upstream_node.get_parameter_value(upstream_parameter.name)
230
230
 
231
231
  # Pass the value through using the same mechanism as normal resolution
232
- GriptapeNodes.get_instance().handle_request(
233
- SetParameterValueRequest(
234
- parameter_name=parameter.name,
235
- node_name=current_node.name,
236
- value=output_value,
237
- data_type=upstream_parameter.output_type,
232
+ # Skip propagation for Control Parameters as they should not receive values
233
+ if (
234
+ ParameterType.attempt_get_builtin(upstream_parameter.output_type)
235
+ != ParameterTypeBuiltin.CONTROL_TYPE
236
+ ):
237
+ GriptapeNodes.get_instance().handle_request(
238
+ SetParameterValueRequest(
239
+ parameter_name=parameter.name,
240
+ node_name=current_node.name,
241
+ value=output_value,
242
+ data_type=upstream_parameter.output_type,
243
+ incoming_connection_source_node_name=upstream_node.name,
244
+ incoming_connection_source_parameter_name=upstream_parameter.name,
245
+ )
238
246
  )
239
- )
240
247
 
241
248
  @staticmethod
242
249
  def on_enter(context: ResolutionContext) -> type[State] | None:
@@ -265,6 +265,50 @@ class SetNodeMetadataResultFailure(ResultPayloadFailure):
265
265
  """Metadata update failed. Common causes: node not found, no current context, invalid metadata format."""
266
266
 
267
267
 
268
+ @dataclass
269
+ @PayloadRegistry.register
270
+ class BatchSetNodeMetadataRequest(RequestPayload):
271
+ """Update metadata for multiple nodes in a single request.
272
+
273
+ Use when: Updating positions for multiple nodes at once, applying bulk styling changes,
274
+ implementing multi-node selection operations, optimizing performance for UI updates.
275
+ Supports partial updates - only specified metadata fields are updated for each node.
276
+
277
+ Args:
278
+ node_metadata_updates: Dictionary mapping node names to their metadata updates.
279
+ Each node's metadata is merged with existing metadata (partial update).
280
+ If a node name is None, uses the current context node.
281
+
282
+ Results: BatchSetNodeMetadataResultSuccess | BatchSetNodeMetadataResultFailure (some nodes not found, update errors)
283
+ """
284
+
285
+ node_metadata_updates: dict[str | None, dict[str, Any]]
286
+
287
+
288
+ @dataclass
289
+ @PayloadRegistry.register
290
+ class BatchSetNodeMetadataResultSuccess(WorkflowAlteredMixin, ResultPayloadSuccess):
291
+ """Batch node metadata update completed successfully.
292
+
293
+ Args:
294
+ updated_nodes: List of node names that were successfully updated
295
+ failed_nodes: Dictionary mapping failed node names to error descriptions (if any)
296
+ """
297
+
298
+ updated_nodes: list[str]
299
+ failed_nodes: dict[str, str] = field(default_factory=dict)
300
+
301
+
302
+ @dataclass
303
+ @PayloadRegistry.register
304
+ class BatchSetNodeMetadataResultFailure(ResultPayloadFailure):
305
+ """Batch metadata update failed.
306
+
307
+ Common causes: all nodes not found, no current context, invalid metadata format,
308
+ or other systemic errors preventing the batch operation.
309
+ """
310
+
311
+
268
312
  # Get all info via a "jumbo" node event. Batches multiple info requests for, say, a GUI.
269
313
  # ...jumbode?
270
314
  @dataclass
@@ -11,6 +11,7 @@ from griptape_nodes.exe_types.core_types import (
11
11
  Parameter,
12
12
  ParameterContainer,
13
13
  ParameterMode,
14
+ ParameterType,
14
15
  ParameterTypeBuiltin,
15
16
  )
16
17
  from griptape_nodes.exe_types.flow import ControlFlow
@@ -853,8 +854,15 @@ class FlowManager:
853
854
  value = None
854
855
  if isinstance(target_param, ParameterContainer):
855
856
  target_node.kill_parameter_children(target_param)
856
- # if it existed somewhere and actually has a value - Set the parameter!
857
- if value and request.initial_setup is False:
857
+ # Set the parameter value (including None/empty values) unless we're in initial setup
858
+ # Skip propagation for Control Parameters as they should not receive values
859
+ if (
860
+ request.initial_setup is False
861
+ and ParameterType.attempt_get_builtin(source_param.output_type) != ParameterTypeBuiltin.CONTROL_TYPE
862
+ ):
863
+ # When creating a connection, pass the initial value from source to target parameter
864
+ # Set incoming_connection_source fields to identify this as legitimate connection value passing
865
+ # (not manual property setting) so it bypasses the INPUT+PROPERTY connection blocking logic
858
866
  GriptapeNodes.handle_request(
859
867
  SetParameterValueRequest(
860
868
  parameter_name=target_param.name,
@@ -1905,6 +1913,7 @@ class FlowManager:
1905
1913
  valid_data_nodes = []
1906
1914
  start_nodes = []
1907
1915
  control_nodes = []
1916
+ cn_mgr = self.get_connections()
1908
1917
  for node in all_nodes:
1909
1918
  # if it's a start node, start here! Return the first one!
1910
1919
  if isinstance(node, StartNode):
@@ -1915,15 +1924,21 @@ class FlowManager:
1915
1924
  control_param = False
1916
1925
  for parameter in node.parameters:
1917
1926
  if ParameterTypeBuiltin.CONTROL_TYPE.value == parameter.output_type:
1918
- control_param = True
1919
- break
1927
+ # Check if the control parameters are being used at all. If they are not, treat it as a data node.
1928
+ incoming_control = (
1929
+ node.name in cn_mgr.incoming_index and parameter.name in cn_mgr.incoming_index[node.name]
1930
+ )
1931
+ outgoing_control = (
1932
+ node.name in cn_mgr.outgoing_index and parameter.name in cn_mgr.outgoing_index[node.name]
1933
+ )
1934
+ if incoming_control or outgoing_control:
1935
+ control_param = True
1936
+ break
1920
1937
  if not control_param:
1921
1938
  # saving this for later
1922
1939
  data_nodes.append(node)
1923
1940
  # If this node doesn't have a control connection..
1924
1941
  continue
1925
-
1926
- cn_mgr = self.get_connections()
1927
1942
  # check if it has an incoming connection. If it does, it's not a start node
1928
1943
  has_control_connection = False
1929
1944
  if node.name in cn_mgr.incoming_index:
@@ -1931,10 +1946,19 @@ class FlowManager:
1931
1946
  param = node.get_parameter_by_name(param_name)
1932
1947
  if param and ParameterTypeBuiltin.CONTROL_TYPE.value == param.output_type:
1933
1948
  # there is a control connection coming in
1949
+ # If the node is a StartLoopNode, it may have an incoming hidden connection from it's EndLoopNode for iteration.
1950
+ if isinstance(node, StartLoopNode):
1951
+ connection_id = cn_mgr.incoming_index[node.name][param_name][0]
1952
+ connection = cn_mgr.connections[connection_id]
1953
+ connected_node = connection.get_source_node()
1954
+ # Check if the source node is the end loop node associated with this StartLoopNode.
1955
+ # If it is, then this could still be the first node in the control flow.
1956
+ if connected_node == node.end_node:
1957
+ continue
1934
1958
  has_control_connection = True
1935
1959
  break
1936
1960
  # if there is a connection coming in, isn't a start.
1937
- if has_control_connection and not isinstance(node, StartLoopNode):
1961
+ if has_control_connection:
1938
1962
  continue
1939
1963
  # Does it have an outgoing connection?
1940
1964
  if node.name in cn_mgr.outgoing_index:
@@ -10,6 +10,7 @@ from griptape_nodes.exe_types.core_types import (
10
10
  ParameterContainer,
11
11
  ParameterGroup,
12
12
  ParameterMode,
13
+ ParameterType,
13
14
  ParameterTypeBuiltin,
14
15
  )
15
16
  from griptape_nodes.exe_types.flow import ControlFlow
@@ -53,6 +54,9 @@ from griptape_nodes.retained_mode.events.library_events import (
53
54
  GetLibraryMetadataResultSuccess,
54
55
  )
55
56
  from griptape_nodes.retained_mode.events.node_events import (
57
+ BatchSetNodeMetadataRequest,
58
+ BatchSetNodeMetadataResultFailure,
59
+ BatchSetNodeMetadataResultSuccess,
56
60
  CreateNodeRequest,
57
61
  CreateNodeResultFailure,
58
62
  CreateNodeResultSuccess,
@@ -152,6 +156,9 @@ class NodeManager:
152
156
  )
153
157
  event_manager.assign_manager_to_request_type(GetNodeMetadataRequest, self.on_get_node_metadata_request)
154
158
  event_manager.assign_manager_to_request_type(SetNodeMetadataRequest, self.on_set_node_metadata_request)
159
+ event_manager.assign_manager_to_request_type(
160
+ BatchSetNodeMetadataRequest, self.on_batch_set_node_metadata_request
161
+ )
155
162
  event_manager.assign_manager_to_request_type(
156
163
  ListConnectionsForNodeRequest, self.on_list_connections_for_node_request
157
164
  )
@@ -665,6 +672,46 @@ class NodeManager:
665
672
  result = SetNodeMetadataResultSuccess()
666
673
  return result
667
674
 
675
+ def on_batch_set_node_metadata_request(self, request: BatchSetNodeMetadataRequest) -> ResultPayload:
676
+ updated_nodes = []
677
+ failed_nodes = {}
678
+
679
+ for node_name, metadata_update in request.node_metadata_updates.items():
680
+ # Resolve node name and get node object
681
+ node = None
682
+ if node_name is None:
683
+ # Get from current context
684
+ if not GriptapeNodes.ContextManager().has_current_node():
685
+ failed_nodes["current_context"] = "No current context node available"
686
+ continue
687
+ node = GriptapeNodes.ContextManager().get_current_node()
688
+ actual_node_name = node.name
689
+ else:
690
+ actual_node_name = node_name
691
+
692
+ # Look up node if we don't have it yet
693
+ if node is None:
694
+ obj_mgr = GriptapeNodes.ObjectManager()
695
+ node = obj_mgr.attempt_get_object_by_name_as_type(actual_node_name, BaseNode)
696
+ if node is None:
697
+ failed_nodes[actual_node_name] = f"Node '{actual_node_name}' not found"
698
+ continue
699
+
700
+ single_request = SetNodeMetadataRequest(node_name=actual_node_name, metadata=metadata_update)
701
+ result = self.on_set_node_metadata_request(single_request)
702
+
703
+ if isinstance(result, SetNodeMetadataResultSuccess):
704
+ updated_nodes.append(actual_node_name)
705
+ else:
706
+ failed_nodes[actual_node_name] = result.result_details
707
+
708
+ if not updated_nodes:
709
+ return BatchSetNodeMetadataResultFailure(
710
+ result_details=f"Failed to update any nodes. Failed nodes: {failed_nodes}"
711
+ )
712
+
713
+ return BatchSetNodeMetadataResultSuccess(updated_nodes=updated_nodes, failed_nodes=failed_nodes)
714
+
668
715
  def on_list_connections_for_node_request(self, request: ListConnectionsForNodeRequest) -> ResultPayload:
669
716
  node_name = request.node_name
670
717
  node = None
@@ -1553,14 +1600,18 @@ class NodeManager:
1553
1600
  # Optional data_type parameter for internal handling!
1554
1601
  conn_output_nodes = parent_flow.get_connected_output_parameters(node, parameter)
1555
1602
  for target_node, target_parameter in conn_output_nodes:
1556
- GriptapeNodes.handle_request(
1557
- SetParameterValueRequest(
1558
- parameter_name=target_parameter.name,
1559
- node_name=target_node.name,
1560
- value=finalized_value,
1561
- data_type=object_type, # Do type instead of output type, because it hasn't been processed.
1603
+ # Skip propagation for Control Parameters as they should not receive values
1604
+ if ParameterType.attempt_get_builtin(parameter.output_type) != ParameterTypeBuiltin.CONTROL_TYPE:
1605
+ GriptapeNodes.handle_request(
1606
+ SetParameterValueRequest(
1607
+ parameter_name=target_parameter.name,
1608
+ node_name=target_node.name,
1609
+ value=finalized_value,
1610
+ data_type=object_type, # Do type instead of output type, because it hasn't been processed.
1611
+ incoming_connection_source_node_name=node.name,
1612
+ incoming_connection_source_parameter_name=parameter.name,
1613
+ )
1562
1614
  )
1563
- )
1564
1615
 
1565
1616
  # Cool.
1566
1617
  details = f"Successfully set value on Node '{node_name}' Parameter '{request.parameter_name}'."