griptape-nodes 0.63.10__py3-none-any.whl → 0.64.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/common/node_executor.py +95 -171
- griptape_nodes/exe_types/connections.py +51 -2
- griptape_nodes/exe_types/flow.py +3 -3
- griptape_nodes/exe_types/node_types.py +330 -202
- griptape_nodes/exe_types/param_components/artifact_url/__init__.py +1 -0
- griptape_nodes/exe_types/param_components/artifact_url/public_artifact_url_parameter.py +155 -0
- griptape_nodes/exe_types/param_components/progress_bar_component.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_string.py +27 -0
- griptape_nodes/machines/control_flow.py +64 -203
- griptape_nodes/machines/dag_builder.py +85 -238
- griptape_nodes/machines/parallel_resolution.py +9 -236
- griptape_nodes/machines/sequential_resolution.py +133 -11
- griptape_nodes/retained_mode/events/agent_events.py +2 -0
- griptape_nodes/retained_mode/events/flow_events.py +5 -6
- griptape_nodes/retained_mode/events/node_events.py +151 -1
- griptape_nodes/retained_mode/events/workflow_events.py +10 -0
- griptape_nodes/retained_mode/managers/agent_manager.py +33 -1
- griptape_nodes/retained_mode/managers/flow_manager.py +213 -290
- griptape_nodes/retained_mode/managers/library_manager.py +24 -7
- griptape_nodes/retained_mode/managers/node_manager.py +400 -77
- griptape_nodes/retained_mode/managers/version_compatibility_manager.py +113 -69
- griptape_nodes/retained_mode/managers/workflow_manager.py +45 -10
- griptape_nodes/servers/mcp.py +32 -0
- griptape_nodes/version_compatibility/versions/v0_63_8/__init__.py +1 -0
- griptape_nodes/version_compatibility/versions/v0_63_8/deprecated_nodegroup_parameters.py +105 -0
- {griptape_nodes-0.63.10.dist-info → griptape_nodes-0.64.1.dist-info}/METADATA +3 -1
- {griptape_nodes-0.63.10.dist-info → griptape_nodes-0.64.1.dist-info}/RECORD +31 -28
- griptape_nodes/version_compatibility/workflow_versions/__init__.py +0 -1
- /griptape_nodes/version_compatibility/{workflow_versions → versions}/v0_7_0/__init__.py +0 -0
- /griptape_nodes/version_compatibility/{workflow_versions → versions}/v0_7_0/local_executor_argument_addition.py +0 -0
- {griptape_nodes-0.63.10.dist-info → griptape_nodes-0.64.1.dist-info}/WHEEL +0 -0
- {griptape_nodes-0.63.10.dist-info → griptape_nodes-0.64.1.dist-info}/entry_points.txt +0 -0
|
@@ -4,7 +4,7 @@ import importlib
|
|
|
4
4
|
import logging
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import TYPE_CHECKING, NamedTuple
|
|
7
|
+
from typing import TYPE_CHECKING, Any, NamedTuple
|
|
8
8
|
|
|
9
9
|
import semver
|
|
10
10
|
|
|
@@ -35,8 +35,13 @@ from griptape_nodes.retained_mode.managers.fitness_problems.workflows.node_type_
|
|
|
35
35
|
from griptape_nodes.retained_mode.managers.library_lifecycle.library_status import LibraryStatus
|
|
36
36
|
|
|
37
37
|
if TYPE_CHECKING:
|
|
38
|
+
from griptape_nodes.exe_types.node_types import BaseNode
|
|
38
39
|
from griptape_nodes.node_library.library_registry import LibrarySchema
|
|
39
40
|
from griptape_nodes.node_library.workflow_registry import WorkflowMetadata
|
|
41
|
+
from griptape_nodes.retained_mode.events.parameter_events import (
|
|
42
|
+
SetParameterValueResultFailure,
|
|
43
|
+
SetParameterValueResultSuccess,
|
|
44
|
+
)
|
|
40
45
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
41
46
|
from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
|
|
42
47
|
from griptape_nodes.retained_mode.managers.fitness_problems.workflows.workflow_problem import WorkflowProblem
|
|
@@ -83,6 +88,38 @@ class WorkflowVersionCompatibilityCheck(ABC):
|
|
|
83
88
|
"""Perform the workflow compatibility check."""
|
|
84
89
|
|
|
85
90
|
|
|
91
|
+
class SetParameterVersionCompatibilityCheck(ABC):
|
|
92
|
+
"""Abstract base class for runtime parameter set version compatibility checks."""
|
|
93
|
+
|
|
94
|
+
@abstractmethod
|
|
95
|
+
def applies_to_set_parameter(self, node: BaseNode, parameter_name: str, value: Any) -> bool:
|
|
96
|
+
"""Return True if this check applies to the given parameter set operation.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
node: The node instance
|
|
100
|
+
parameter_name: Name of the parameter being set
|
|
101
|
+
value: The value being set
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
True if this check should be performed for this parameter
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
@abstractmethod
|
|
108
|
+
def set_parameter_value(
|
|
109
|
+
self, node: BaseNode, parameter_name: str, value: Any
|
|
110
|
+
) -> SetParameterValueResultSuccess | SetParameterValueResultFailure:
|
|
111
|
+
"""Handle setting the parameter value with version compatibility logic.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
node: The node instance
|
|
115
|
+
parameter_name: Name of the parameter being set
|
|
116
|
+
value: The value being set
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
SetParameterValueResultSuccess or SetParameterValueResultFailure
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
|
|
86
123
|
class VersionCompatibilityManager:
|
|
87
124
|
"""Manages version compatibility checks for libraries and other components."""
|
|
88
125
|
|
|
@@ -90,89 +127,74 @@ class VersionCompatibilityManager:
|
|
|
90
127
|
self._event_manager = event_manager
|
|
91
128
|
self._compatibility_checks: list[LibraryVersionCompatibilityCheck] = []
|
|
92
129
|
self._workflow_compatibility_checks: list[WorkflowVersionCompatibilityCheck] = []
|
|
130
|
+
self._set_parameter_compatibility_checks: list[SetParameterVersionCompatibilityCheck] = []
|
|
93
131
|
self._discover_version_checks()
|
|
94
132
|
|
|
95
133
|
def _discover_version_checks(self) -> None:
|
|
96
|
-
"""Automatically discover and register
|
|
97
|
-
|
|
98
|
-
|
|
134
|
+
"""Automatically discover and register all version compatibility checks from the versions/ directory."""
|
|
135
|
+
try:
|
|
136
|
+
import griptape_nodes.version_compatibility.versions as versions_module
|
|
99
137
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
import griptape_nodes.version_compatibility.versions as versions_module
|
|
138
|
+
if versions_module.__file__ is None:
|
|
139
|
+
logger.debug("No version compatibility checks directory found, skipping discovery")
|
|
140
|
+
return
|
|
104
141
|
|
|
105
|
-
|
|
142
|
+
versions_path = Path(versions_module.__file__).parent
|
|
106
143
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
144
|
+
# Iterate through version directories (e.g., v0_39_0, v0_63_8)
|
|
145
|
+
for version_dir in versions_path.iterdir():
|
|
146
|
+
if not version_dir.is_dir() or version_dir.name.startswith("__"):
|
|
147
|
+
continue
|
|
111
148
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
149
|
+
# Iterate through Python files in the version directory
|
|
150
|
+
for check_file in version_dir.glob("*.py"):
|
|
151
|
+
if check_file.name.startswith("__"):
|
|
152
|
+
continue
|
|
153
|
+
|
|
154
|
+
# Import the module once
|
|
155
|
+
file_module_path = (
|
|
156
|
+
f"griptape_nodes.version_compatibility.versions.{version_dir.name}.{check_file.stem}"
|
|
157
|
+
)
|
|
158
|
+
try:
|
|
159
|
+
check_module = importlib.import_module(file_module_path)
|
|
160
|
+
except ImportError as e:
|
|
161
|
+
logger.debug("Failed to import check module %s: %s", file_module_path, e)
|
|
162
|
+
continue
|
|
116
163
|
|
|
117
|
-
|
|
164
|
+
# Scan and register all check types in this module
|
|
165
|
+
self._register_checks_from_module(check_module)
|
|
118
166
|
|
|
119
|
-
# Iterate through version directories
|
|
120
|
-
for version_dir in workflow_versions_path.iterdir():
|
|
121
|
-
if version_dir.is_dir() and not version_dir.name.startswith("__"):
|
|
122
|
-
self._discover_workflow_checks_in_version_dir(version_dir)
|
|
123
167
|
except ImportError:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
"""Discover compatibility checks in a specific version directory."""
|
|
129
|
-
# Iterate through Python files in the version directory
|
|
130
|
-
for check_file in version_dir.glob("*.py"):
|
|
131
|
-
if check_file.name.startswith("__"):
|
|
132
|
-
continue
|
|
168
|
+
logger.debug("No version compatibility checks directory found, skipping discovery")
|
|
169
|
+
|
|
170
|
+
def _register_checks_from_module(self, check_module: Any) -> None:
|
|
171
|
+
"""Register all version compatibility checks found in a module.
|
|
133
172
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
attr = getattr(module, attr_name)
|
|
141
|
-
if (
|
|
142
|
-
isinstance(attr, type)
|
|
143
|
-
and issubclass(attr, LibraryVersionCompatibilityCheck)
|
|
144
|
-
and attr is not LibraryVersionCompatibilityCheck
|
|
145
|
-
):
|
|
146
|
-
check_instance = attr()
|
|
147
|
-
self._compatibility_checks.append(check_instance)
|
|
148
|
-
logger.debug("Registered library version compatibility check: %s", attr_name)
|
|
149
|
-
|
|
150
|
-
def _discover_workflow_checks_in_version_dir(self, version_dir: Path) -> None:
|
|
151
|
-
"""Discover workflow compatibility checks in a specific version directory."""
|
|
152
|
-
# Iterate through Python files in the version directory
|
|
153
|
-
for check_file in version_dir.glob("*.py"):
|
|
154
|
-
if check_file.name.startswith("__"):
|
|
173
|
+
Args:
|
|
174
|
+
check_module: The imported module to scan for check classes
|
|
175
|
+
"""
|
|
176
|
+
for attr_name in dir(check_module):
|
|
177
|
+
attr = getattr(check_module, attr_name)
|
|
178
|
+
if not isinstance(attr, type):
|
|
155
179
|
continue
|
|
156
180
|
|
|
157
|
-
#
|
|
158
|
-
|
|
159
|
-
try:
|
|
160
|
-
module = importlib.import_module(module_path)
|
|
161
|
-
except ImportError as e:
|
|
162
|
-
logger.debug("Failed to import workflow compatibility check module %s: %s", module_path, e)
|
|
181
|
+
# Skip abstract base classes
|
|
182
|
+
if ABC in getattr(attr, "__bases__", ()):
|
|
163
183
|
continue
|
|
164
184
|
|
|
165
|
-
#
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
185
|
+
# Register based on which base class it inherits from
|
|
186
|
+
if issubclass(attr, LibraryVersionCompatibilityCheck):
|
|
187
|
+
check_instance = attr()
|
|
188
|
+
self._compatibility_checks.append(check_instance)
|
|
189
|
+
logger.debug("Registered library version compatibility check: %s", attr_name)
|
|
190
|
+
elif issubclass(attr, WorkflowVersionCompatibilityCheck):
|
|
191
|
+
check_instance = attr()
|
|
192
|
+
self._workflow_compatibility_checks.append(check_instance)
|
|
193
|
+
logger.debug("Registered workflow version compatibility check: %s", attr_name)
|
|
194
|
+
elif issubclass(attr, SetParameterVersionCompatibilityCheck):
|
|
195
|
+
check_instance = attr()
|
|
196
|
+
self._set_parameter_compatibility_checks.append(check_instance)
|
|
197
|
+
logger.debug("Registered set parameter version compatibility check: %s", attr_name)
|
|
176
198
|
|
|
177
199
|
def _check_library_for_deprecated_nodes(
|
|
178
200
|
self, library_data: LibrarySchema
|
|
@@ -333,6 +355,28 @@ class VersionCompatibilityManager:
|
|
|
333
355
|
|
|
334
356
|
return issues
|
|
335
357
|
|
|
358
|
+
def check_set_parameter_version_compatibility(
|
|
359
|
+
self, node: BaseNode, parameter_name: str, value: Any
|
|
360
|
+
) -> SetParameterValueResultSuccess | SetParameterValueResultFailure | None:
|
|
361
|
+
"""Check if a parameter set operation requires version compatibility handling.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
node: The node instance
|
|
365
|
+
parameter_name: Name of the parameter being set
|
|
366
|
+
value: The value being set
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
SetParameterValueResultSuccess, SetParameterValueResultFailure, or None if no check applies
|
|
370
|
+
"""
|
|
371
|
+
# Iterate through registered checks and find the first one that applies
|
|
372
|
+
for check_instance in self._set_parameter_compatibility_checks:
|
|
373
|
+
if check_instance.applies_to_set_parameter(node, parameter_name, value):
|
|
374
|
+
# First matching check handles the parameter
|
|
375
|
+
return check_instance.set_parameter_value(node, parameter_name, value)
|
|
376
|
+
|
|
377
|
+
# No checks applied
|
|
378
|
+
return None
|
|
379
|
+
|
|
336
380
|
def _get_current_engine_version(self) -> semver.VersionInfo:
|
|
337
381
|
"""Get the current engine version."""
|
|
338
382
|
result = GriptapeNodes.handle_request(GetEngineVersionRequest())
|
|
@@ -14,6 +14,7 @@ from pathlib import Path
|
|
|
14
14
|
from typing import TYPE_CHECKING, Any, ClassVar, NamedTuple, TypeVar, cast
|
|
15
15
|
|
|
16
16
|
import aiofiles
|
|
17
|
+
import portalocker
|
|
17
18
|
import semver
|
|
18
19
|
import tomlkit
|
|
19
20
|
from rich.box import HEAVY_EDGE
|
|
@@ -1269,9 +1270,12 @@ class WorkflowManager:
|
|
|
1269
1270
|
success: bool
|
|
1270
1271
|
error_details: str
|
|
1271
1272
|
|
|
1272
|
-
|
|
1273
|
+
def _write_workflow_file(self, file_path: Path, content: str, file_name: str) -> WriteWorkflowFileResult:
|
|
1273
1274
|
"""Write workflow content to file with proper validation and error handling.
|
|
1274
1275
|
|
|
1276
|
+
Uses portalocker for exclusive file locking to prevent concurrent writes.
|
|
1277
|
+
First write wins - if another process is writing, this call fails immediately.
|
|
1278
|
+
|
|
1275
1279
|
Args:
|
|
1276
1280
|
file_path: Path where to write the file
|
|
1277
1281
|
content: Content to write
|
|
@@ -1295,13 +1299,34 @@ class WorkflowManager:
|
|
|
1295
1299
|
details = f"Attempted to save workflow '{file_name}'. Failed when creating directory structure: {e}"
|
|
1296
1300
|
return self.WriteWorkflowFileResult(success=False, error_details=details)
|
|
1297
1301
|
|
|
1298
|
-
# Write the file content
|
|
1302
|
+
# Write the file content with exclusive lock (non-blocking)
|
|
1303
|
+
error_details = None
|
|
1299
1304
|
try:
|
|
1300
|
-
|
|
1301
|
-
|
|
1305
|
+
with portalocker.Lock(
|
|
1306
|
+
file_path,
|
|
1307
|
+
mode="w",
|
|
1308
|
+
encoding="utf-8",
|
|
1309
|
+
timeout=0, # Non-blocking: fail immediately if locked
|
|
1310
|
+
flags=portalocker.LockFlags.EXCLUSIVE,
|
|
1311
|
+
) as fh:
|
|
1312
|
+
fh.write(content)
|
|
1313
|
+
except portalocker.LockException:
|
|
1314
|
+
error_details = (
|
|
1315
|
+
f"Attempted to save workflow '{file_name}'. Another process is currently writing to this workflow file"
|
|
1316
|
+
)
|
|
1317
|
+
except PermissionError as e:
|
|
1318
|
+
error_details = f"Attempted to save workflow '{file_name}'. Permission denied: {e}"
|
|
1319
|
+
except IsADirectoryError:
|
|
1320
|
+
error_details = f"Attempted to save workflow '{file_name}'. Path is a directory, not a file"
|
|
1321
|
+
except UnicodeEncodeError as e:
|
|
1322
|
+
error_details = f"Attempted to save workflow '{file_name}'. Content encoding error: {e}"
|
|
1302
1323
|
except OSError as e:
|
|
1303
|
-
|
|
1304
|
-
|
|
1324
|
+
error_details = f"Attempted to save workflow '{file_name}'. OS error: {e}"
|
|
1325
|
+
except Exception as e:
|
|
1326
|
+
error_details = f"Attempted to save workflow '{file_name}'. Unexpected error: {type(e).__name__}: {e}"
|
|
1327
|
+
|
|
1328
|
+
if error_details:
|
|
1329
|
+
return self.WriteWorkflowFileResult(success=False, error_details=error_details)
|
|
1305
1330
|
|
|
1306
1331
|
return self.WriteWorkflowFileResult(success=True, error_details="")
|
|
1307
1332
|
|
|
@@ -1546,7 +1571,10 @@ class WorkflowManager:
|
|
|
1546
1571
|
return SaveWorkflowFileFromSerializedFlowResultFailure(result_details=details)
|
|
1547
1572
|
|
|
1548
1573
|
# Write the workflow file
|
|
1549
|
-
|
|
1574
|
+
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/3169
|
|
1575
|
+
# This is a synchronous call within an async context and may block the event loop.
|
|
1576
|
+
# Consider using asyncio.to_thread() to run in a thread pool for better async performance.
|
|
1577
|
+
write_result = self._write_workflow_file(file_path, final_code_output, request.file_name)
|
|
1550
1578
|
if not write_result.success:
|
|
1551
1579
|
return SaveWorkflowFileFromSerializedFlowResultFailure(result_details=write_result.error_details)
|
|
1552
1580
|
|
|
@@ -2901,6 +2929,7 @@ class WorkflowManager:
|
|
|
2901
2929
|
import_recorder.add_from_import("griptape_nodes.node_library.library_registry", "NodeDeprecationMetadata")
|
|
2902
2930
|
import_recorder.add_from_import("griptape_nodes.node_library.library_registry", "IconVariant")
|
|
2903
2931
|
import_recorder.add_from_import("griptape_nodes.retained_mode.events.node_events", "CreateNodeRequest")
|
|
2932
|
+
import_recorder.add_from_import("griptape_nodes.retained_mode.events.node_events", "CreateNodeGroupRequest")
|
|
2904
2933
|
import_recorder.add_from_import(
|
|
2905
2934
|
"griptape_nodes.retained_mode.events.parameter_events", "AddParameterToNodeRequest"
|
|
2906
2935
|
)
|
|
@@ -2925,7 +2954,8 @@ class WorkflowManager:
|
|
|
2925
2954
|
create_node_request_args.append(
|
|
2926
2955
|
ast.keyword(arg=field.name, value=ast.Constant(value=field_value, lineno=1, col_offset=0))
|
|
2927
2956
|
)
|
|
2928
|
-
|
|
2957
|
+
# Get the actual request class name (CreateNodeRequest or CreateNodeGroupRequest)
|
|
2958
|
+
request_class_name = type(create_node_request).__name__
|
|
2929
2959
|
# Handle the create node command and assign to node name
|
|
2930
2960
|
create_node_call_ast = ast.Assign(
|
|
2931
2961
|
targets=[ast.Name(id=node_variable_name, ctx=ast.Store(), lineno=1, col_offset=0)],
|
|
@@ -2940,7 +2970,7 @@ class WorkflowManager:
|
|
|
2940
2970
|
),
|
|
2941
2971
|
args=[
|
|
2942
2972
|
ast.Call(
|
|
2943
|
-
func=ast.Name(id=
|
|
2973
|
+
func=ast.Name(id=request_class_name, ctx=ast.Load(), lineno=1, col_offset=0),
|
|
2944
2974
|
args=[],
|
|
2945
2975
|
keywords=create_node_request_args,
|
|
2946
2976
|
lineno=1,
|
|
@@ -2951,7 +2981,7 @@ class WorkflowManager:
|
|
|
2951
2981
|
lineno=1,
|
|
2952
2982
|
col_offset=0,
|
|
2953
2983
|
),
|
|
2954
|
-
attr="node_name",
|
|
2984
|
+
attr="node_name" if request_class_name == "CreateNodeRequest" else "node_group_name",
|
|
2955
2985
|
ctx=ast.Load(),
|
|
2956
2986
|
lineno=1,
|
|
2957
2987
|
col_offset=0,
|
|
@@ -3004,6 +3034,11 @@ class WorkflowManager:
|
|
|
3004
3034
|
|
|
3005
3035
|
# Generate handle_request calls for element_modification_commands
|
|
3006
3036
|
for element_command in serialized_node_command.element_modification_commands:
|
|
3037
|
+
# Add import for this element command type
|
|
3038
|
+
element_command_class_name = element_command.__class__.__name__
|
|
3039
|
+
element_command_module = element_command.__class__.__module__
|
|
3040
|
+
import_recorder.add_from_import(element_command_module, element_command_class_name)
|
|
3041
|
+
|
|
3007
3042
|
# Strip default values from element_command
|
|
3008
3043
|
element_command_args = []
|
|
3009
3044
|
if is_dataclass(element_command):
|
griptape_nodes/servers/mcp.py
CHANGED
|
@@ -23,23 +23,49 @@ from griptape_nodes.retained_mode.events.connection_events import (
|
|
|
23
23
|
DeleteConnectionRequest,
|
|
24
24
|
ListConnectionsForNodeRequest,
|
|
25
25
|
)
|
|
26
|
+
from griptape_nodes.retained_mode.events.execution_events import (
|
|
27
|
+
ResolveNodeRequest,
|
|
28
|
+
StartFlowFromNodeRequest,
|
|
29
|
+
StartFlowRequest,
|
|
30
|
+
)
|
|
26
31
|
from griptape_nodes.retained_mode.events.flow_events import ListNodesInFlowRequest
|
|
32
|
+
from griptape_nodes.retained_mode.events.library_events import (
|
|
33
|
+
ListCategoriesInLibraryRequest,
|
|
34
|
+
ListNodeTypesInLibraryRequest,
|
|
35
|
+
ListRegisteredLibrariesRequest,
|
|
36
|
+
)
|
|
27
37
|
from griptape_nodes.retained_mode.events.node_events import (
|
|
28
38
|
CreateNodeRequest,
|
|
29
39
|
DeleteNodeRequest,
|
|
30
40
|
GetNodeMetadataRequest,
|
|
31
41
|
GetNodeResolutionStateRequest,
|
|
32
42
|
ListParametersOnNodeRequest,
|
|
43
|
+
ResetNodeToDefaultsRequest,
|
|
44
|
+
SetLockNodeStateRequest,
|
|
33
45
|
SetNodeMetadataRequest,
|
|
34
46
|
)
|
|
47
|
+
from griptape_nodes.retained_mode.events.object_events import RenameObjectRequest
|
|
35
48
|
from griptape_nodes.retained_mode.events.parameter_events import (
|
|
49
|
+
GetConnectionsForParameterRequest,
|
|
50
|
+
GetParameterDetailsRequest,
|
|
36
51
|
GetParameterValueRequest,
|
|
37
52
|
SetParameterValueRequest,
|
|
38
53
|
)
|
|
54
|
+
from griptape_nodes.retained_mode.events.workflow_events import RunWorkflowWithCurrentStateRequest
|
|
39
55
|
from griptape_nodes.retained_mode.managers.config_manager import ConfigManager
|
|
40
56
|
from griptape_nodes.retained_mode.managers.secrets_manager import SecretsManager
|
|
41
57
|
|
|
42
58
|
SUPPORTED_REQUEST_EVENTS: dict[str, type[RequestPayload]] = {
|
|
59
|
+
# Workflows
|
|
60
|
+
"RunWorkflowWithCurrentStateRequest": RunWorkflowWithCurrentStateRequest,
|
|
61
|
+
# Libraries
|
|
62
|
+
"ListRegisteredLibrariesRequest": ListRegisteredLibrariesRequest,
|
|
63
|
+
"ListNodeTypesInLibraryRequest": ListNodeTypesInLibraryRequest,
|
|
64
|
+
"ListCategoriesInLibraryRequest": ListCategoriesInLibraryRequest,
|
|
65
|
+
# Execution
|
|
66
|
+
"ResolveNodeRequest": ResolveNodeRequest,
|
|
67
|
+
"StartFlowRequest": StartFlowRequest,
|
|
68
|
+
"StartFlowFromNodeRequest": StartFlowFromNodeRequest,
|
|
43
69
|
# Nodes
|
|
44
70
|
"CreateNodeRequest": CreateNodeRequest,
|
|
45
71
|
"DeleteNodeRequest": DeleteNodeRequest,
|
|
@@ -47,6 +73,10 @@ SUPPORTED_REQUEST_EVENTS: dict[str, type[RequestPayload]] = {
|
|
|
47
73
|
"GetNodeResolutionStateRequest": GetNodeResolutionStateRequest,
|
|
48
74
|
"GetNodeMetadataRequest": GetNodeMetadataRequest,
|
|
49
75
|
"SetNodeMetadataRequest": SetNodeMetadataRequest,
|
|
76
|
+
"ResetNodeToDefaultsRequest": ResetNodeToDefaultsRequest,
|
|
77
|
+
"SetLockNodeStateRequest": SetLockNodeStateRequest,
|
|
78
|
+
# Objects
|
|
79
|
+
"RenameObjectRequest": RenameObjectRequest,
|
|
50
80
|
# Connections
|
|
51
81
|
"CreateConnectionRequest": CreateConnectionRequest,
|
|
52
82
|
"DeleteConnectionRequest": DeleteConnectionRequest,
|
|
@@ -55,6 +85,8 @@ SUPPORTED_REQUEST_EVENTS: dict[str, type[RequestPayload]] = {
|
|
|
55
85
|
"ListParametersOnNodeRequest": ListParametersOnNodeRequest,
|
|
56
86
|
"GetParameterValueRequest": GetParameterValueRequest,
|
|
57
87
|
"SetParameterValueRequest": SetParameterValueRequest,
|
|
88
|
+
"GetParameterDetailsRequest": GetParameterDetailsRequest,
|
|
89
|
+
"GetConnectionsForParameterRequest": GetConnectionsForParameterRequest,
|
|
58
90
|
}
|
|
59
91
|
|
|
60
92
|
GTN_MCP_SERVER_HOST = os.getenv("GTN_MCP_SERVER_HOST", "localhost")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Version 0.63.8 parameter compatibility checks."""
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Check for deprecated job_group and execution_environment parameters."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import TYPE_CHECKING, Any, ClassVar
|
|
7
|
+
|
|
8
|
+
import semver
|
|
9
|
+
|
|
10
|
+
from griptape_nodes.exe_types.node_types import NodeGroupNode
|
|
11
|
+
from griptape_nodes.retained_mode.events.app_events import (
|
|
12
|
+
GetEngineVersionRequest,
|
|
13
|
+
GetEngineVersionResultSuccess,
|
|
14
|
+
)
|
|
15
|
+
from griptape_nodes.retained_mode.events.parameter_events import SetParameterValueResultSuccess
|
|
16
|
+
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
17
|
+
from griptape_nodes.retained_mode.managers.version_compatibility_manager import (
|
|
18
|
+
SetParameterVersionCompatibilityCheck,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from griptape_nodes.exe_types.node_types import BaseNode
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger("griptape_nodes")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DeprecatedNodeGroupParametersCheck(SetParameterVersionCompatibilityCheck):
|
|
28
|
+
"""Check for deprecated job_group and execution_environment parameters.
|
|
29
|
+
|
|
30
|
+
These parameters were removed in engine version 0.63.8 for all nodes except NodeGroup.
|
|
31
|
+
This check intercepts attempts to set these parameters and logs a warning prompting
|
|
32
|
+
users to resave their workflows.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
DEPRECATED_PARAMETERS: ClassVar[set[str]] = {"job_group", "execution_environment"}
|
|
36
|
+
REMOVAL_VERSION: ClassVar[semver.VersionInfo] = semver.VersionInfo(0, 63, 8)
|
|
37
|
+
|
|
38
|
+
def __init__(self) -> None:
|
|
39
|
+
"""Initialize the check with an empty set of warned workflows."""
|
|
40
|
+
super().__init__()
|
|
41
|
+
self._warned_workflows: set[str] = set()
|
|
42
|
+
|
|
43
|
+
def applies_to_set_parameter(self, node: BaseNode, parameter_name: str, _value: Any) -> bool:
|
|
44
|
+
"""Return True if this is a deprecated parameter on a non-NodeGroup node.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
node: The node instance
|
|
48
|
+
parameter_name: Name of the parameter being set
|
|
49
|
+
_value: The value being set (unused)
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
True if this check should handle this parameter
|
|
53
|
+
"""
|
|
54
|
+
# Check parameter name first (fastest check)
|
|
55
|
+
if parameter_name not in self.DEPRECATED_PARAMETERS:
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
# Check if node is NOT a NodeGroup (we only block for non-NodeGroup nodes)
|
|
59
|
+
if isinstance(node, NodeGroupNode):
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
# Check if current engine version is >= 0.63.8
|
|
63
|
+
engine_version_result = GriptapeNodes.handle_request(GetEngineVersionRequest())
|
|
64
|
+
if not isinstance(engine_version_result, GetEngineVersionResultSuccess):
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
current_version = semver.VersionInfo(
|
|
68
|
+
engine_version_result.major, engine_version_result.minor, engine_version_result.patch
|
|
69
|
+
)
|
|
70
|
+
return current_version >= self.REMOVAL_VERSION
|
|
71
|
+
|
|
72
|
+
def set_parameter_value(self, _node: BaseNode, parameter_name: str, _value: Any) -> SetParameterValueResultSuccess:
|
|
73
|
+
"""Handle the deprecated parameter by logging a warning and returning success with empty value.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
_node: The node instance (unused)
|
|
77
|
+
parameter_name: Name of the parameter being set
|
|
78
|
+
_value: The value being set (unused)
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
SetParameterValueResultSuccess with empty list value
|
|
82
|
+
"""
|
|
83
|
+
# Get the current workflow name to track warnings per workflow
|
|
84
|
+
workflow_name = GriptapeNodes.ContextManager().get_current_workflow_name()
|
|
85
|
+
|
|
86
|
+
# Check if we've already warned for this workflow
|
|
87
|
+
if workflow_name not in self._warned_workflows:
|
|
88
|
+
# Mark this workflow as warned
|
|
89
|
+
self._warned_workflows.add(workflow_name)
|
|
90
|
+
|
|
91
|
+
# Log warning with all deprecated parameters
|
|
92
|
+
deprecated_params_list = ", ".join(f"'{param}'" for param in self.DEPRECATED_PARAMETERS)
|
|
93
|
+
logger.warning(
|
|
94
|
+
"This workflow uses deprecated parameters (%s) that were removed in engine version %s. "
|
|
95
|
+
"Please resave your workflow and this warning will go away.",
|
|
96
|
+
deprecated_params_list,
|
|
97
|
+
self.REMOVAL_VERSION,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Return success with None as the value (parameter doesn't exist, so no meaningful value to return)
|
|
101
|
+
return SetParameterValueResultSuccess(
|
|
102
|
+
finalized_value=None,
|
|
103
|
+
data_type="any",
|
|
104
|
+
result_details=f"Parameter '{parameter_name}' was removed in v{self.REMOVAL_VERSION}. Please resave this workflow.",
|
|
105
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: griptape-nodes
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.64.1
|
|
4
4
|
Summary: Add your description here
|
|
5
5
|
Requires-Dist: griptape>=1.8.12
|
|
6
6
|
Requires-Dist: pydantic>=2.10.6
|
|
@@ -27,6 +27,7 @@ Requires-Dist: aiofiles>=25.1.0
|
|
|
27
27
|
Requires-Dist: aioshutil>=1.5
|
|
28
28
|
Requires-Dist: ruamel-yaml>=0.18.15
|
|
29
29
|
Requires-Dist: asyncio-thread-runner>=1.0
|
|
30
|
+
Requires-Dist: portalocker>=2.10.0
|
|
30
31
|
Requires-Dist: austin-dist>=3.7.0 ; extra == 'profiling'
|
|
31
32
|
Requires-Python: >=3.12.0, <3.13
|
|
32
33
|
Provides-Extra: profiling
|
|
@@ -55,6 +56,7 @@ This repository contains the Griptape Nodes Engine - the local component that ru
|
|
|
55
56
|
- **📚 Full Documentation:** [docs.griptapenodes.com](https://docs.griptapenodes.com)
|
|
56
57
|
- **⚙️ Installation:** [docs.griptapenodes.com/en/stable/installation/](https://docs.griptapenodes.com/en/latest/installation/)
|
|
57
58
|
- **🔧 Engine Configuration:** [docs.griptapenodes.com/en/stable/configuration/](https://docs.griptapenodes.com/en/latest/configuration/)
|
|
59
|
+
- **📋 Migration Guide:** [MIGRATION.md](MIGRATION.md) - Guide for migrating from deprecated nodes
|
|
58
60
|
|
|
59
61
|
**🧩 Extending Griptape Nodes:**
|
|
60
62
|
|