griptape-nodes 0.43.1__py3-none-any.whl → 0.44.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 +41 -51
- griptape_nodes/app/.python-version +0 -0
- griptape_nodes/app/__init__.py +0 -0
- griptape_nodes/app/api.py +35 -6
- griptape_nodes/app/app.py +0 -0
- griptape_nodes/app/watch.py +0 -0
- griptape_nodes/bootstrap/__init__.py +0 -0
- griptape_nodes/bootstrap/workflow_executors/__init__.py +0 -0
- griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +7 -1
- griptape_nodes/bootstrap/workflow_executors/subprocess_workflow_executor.py +90 -0
- griptape_nodes/bootstrap/workflow_executors/workflow_executor.py +7 -1
- griptape_nodes/drivers/__init__.py +0 -0
- griptape_nodes/drivers/storage/__init__.py +0 -0
- griptape_nodes/drivers/storage/base_storage_driver.py +53 -0
- griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +49 -2
- griptape_nodes/drivers/storage/local_storage_driver.py +37 -0
- griptape_nodes/drivers/storage/storage_backend.py +0 -0
- griptape_nodes/exe_types/__init__.py +0 -0
- griptape_nodes/exe_types/connections.py +0 -0
- griptape_nodes/exe_types/core_types.py +113 -8
- griptape_nodes/exe_types/flow.py +0 -0
- griptape_nodes/exe_types/node_types.py +1 -0
- griptape_nodes/exe_types/type_validator.py +0 -0
- griptape_nodes/machines/__init__.py +0 -0
- griptape_nodes/machines/control_flow.py +5 -4
- griptape_nodes/machines/fsm.py +0 -0
- griptape_nodes/machines/node_resolution.py +110 -74
- griptape_nodes/mcp_server/__init__.py +0 -0
- griptape_nodes/mcp_server/server.py +16 -8
- griptape_nodes/mcp_server/ws_request_manager.py +0 -0
- griptape_nodes/node_library/__init__.py +0 -0
- griptape_nodes/node_library/advanced_node_library.py +0 -0
- griptape_nodes/node_library/library_registry.py +0 -0
- griptape_nodes/node_library/workflow_registry.py +0 -0
- griptape_nodes/py.typed +0 -0
- griptape_nodes/retained_mode/__init__.py +0 -0
- griptape_nodes/retained_mode/events/__init__.py +0 -0
- griptape_nodes/retained_mode/events/agent_events.py +0 -0
- griptape_nodes/retained_mode/events/app_events.py +0 -6
- griptape_nodes/retained_mode/events/arbitrary_python_events.py +0 -0
- griptape_nodes/retained_mode/events/base_events.py +6 -7
- griptape_nodes/retained_mode/events/config_events.py +0 -0
- griptape_nodes/retained_mode/events/connection_events.py +0 -0
- griptape_nodes/retained_mode/events/context_events.py +0 -0
- griptape_nodes/retained_mode/events/execution_events.py +0 -0
- griptape_nodes/retained_mode/events/flow_events.py +2 -1
- griptape_nodes/retained_mode/events/generate_request_payload_schemas.py +0 -0
- griptape_nodes/retained_mode/events/library_events.py +0 -0
- griptape_nodes/retained_mode/events/logger_events.py +0 -0
- griptape_nodes/retained_mode/events/node_events.py +36 -0
- griptape_nodes/retained_mode/events/object_events.py +0 -0
- griptape_nodes/retained_mode/events/os_events.py +98 -6
- griptape_nodes/retained_mode/events/parameter_events.py +0 -0
- griptape_nodes/retained_mode/events/payload_registry.py +0 -0
- griptape_nodes/retained_mode/events/secrets_events.py +0 -0
- griptape_nodes/retained_mode/events/static_file_events.py +0 -0
- griptape_nodes/retained_mode/events/validation_events.py +0 -0
- griptape_nodes/retained_mode/events/workflow_events.py +0 -0
- griptape_nodes/retained_mode/griptape_nodes.py +1 -4
- griptape_nodes/retained_mode/managers/__init__.py +0 -0
- griptape_nodes/retained_mode/managers/agent_manager.py +0 -0
- griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +0 -0
- griptape_nodes/retained_mode/managers/config_manager.py +1 -1
- griptape_nodes/retained_mode/managers/context_manager.py +0 -0
- griptape_nodes/retained_mode/managers/engine_identity_manager.py +0 -0
- griptape_nodes/retained_mode/managers/event_manager.py +0 -0
- griptape_nodes/retained_mode/managers/flow_manager.py +6 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/__init__.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/data_models.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_fsm.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/__init__.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/base.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/github.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/package.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/sandbox.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance.py +0 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_status.py +0 -0
- griptape_nodes/retained_mode/managers/library_manager.py +2 -8
- griptape_nodes/retained_mode/managers/node_manager.py +76 -5
- griptape_nodes/retained_mode/managers/object_manager.py +0 -0
- griptape_nodes/retained_mode/managers/operation_manager.py +0 -0
- griptape_nodes/retained_mode/managers/os_manager.py +133 -8
- griptape_nodes/retained_mode/managers/secrets_manager.py +0 -0
- griptape_nodes/retained_mode/managers/session_manager.py +0 -0
- griptape_nodes/retained_mode/managers/settings.py +0 -0
- griptape_nodes/retained_mode/managers/static_files_manager.py +0 -0
- griptape_nodes/retained_mode/managers/version_compatibility_manager.py +0 -0
- griptape_nodes/retained_mode/managers/workflow_manager.py +54 -5
- griptape_nodes/retained_mode/retained_mode.py +0 -0
- griptape_nodes/retained_mode/utils/__init__.py +0 -0
- griptape_nodes/retained_mode/utils/engine_identity.py +0 -0
- griptape_nodes/retained_mode/utils/name_generator.py +0 -0
- griptape_nodes/traits/__init__.py +0 -0
- griptape_nodes/traits/add_param_button.py +0 -0
- griptape_nodes/traits/button.py +0 -0
- griptape_nodes/traits/clamp.py +0 -0
- griptape_nodes/traits/compare.py +0 -0
- griptape_nodes/traits/compare_images.py +0 -0
- griptape_nodes/traits/file_system_picker.py +18 -0
- griptape_nodes/traits/minmax.py +0 -0
- griptape_nodes/traits/options.py +0 -0
- griptape_nodes/traits/slider.py +0 -0
- griptape_nodes/traits/trait_registry.py +0 -0
- griptape_nodes/traits/traits.json +0 -0
- griptape_nodes/updater/__init__.py +0 -0
- griptape_nodes/updater/__main__.py +0 -0
- griptape_nodes/utils/__init__.py +0 -0
- griptape_nodes/utils/dict_utils.py +0 -0
- griptape_nodes/utils/image_preview.py +0 -0
- griptape_nodes/utils/metaclasses.py +0 -0
- griptape_nodes/utils/version_utils.py +51 -0
- griptape_nodes/version_compatibility/__init__.py +0 -0
- griptape_nodes/version_compatibility/versions/__init__.py +0 -0
- griptape_nodes/version_compatibility/versions/v0_39_0/__init__.py +0 -0
- griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +0 -0
- {griptape_nodes-0.43.1.dist-info → griptape_nodes-0.44.0.dist-info}/METADATA +1 -1
- {griptape_nodes-0.43.1.dist-info → griptape_nodes-0.44.0.dist-info}/RECORD +31 -39
- {griptape_nodes-0.43.1.dist-info → griptape_nodes-0.44.0.dist-info}/WHEEL +1 -1
- griptape_nodes/bootstrap/bootstrap_script.py +0 -54
- griptape_nodes/bootstrap/post_build_install_script.sh +0 -3
- griptape_nodes/bootstrap/pre_build_install_script.sh +0 -4
- griptape_nodes/bootstrap/register_libraries_script.py +0 -32
- griptape_nodes/bootstrap/structure_config.yaml +0 -15
- griptape_nodes/bootstrap/workflow_runners/__init__.py +0 -1
- griptape_nodes/bootstrap/workflow_runners/bootstrap_workflow_runner.py +0 -28
- griptape_nodes/bootstrap/workflow_runners/local_workflow_runner.py +0 -237
- griptape_nodes/bootstrap/workflow_runners/subprocess_workflow_runner.py +0 -62
- griptape_nodes/bootstrap/workflow_runners/workflow_runner.py +0 -11
- {griptape_nodes-0.43.1.dist-info → griptape_nodes-0.44.0.dist-info}/entry_points.txt +0 -0
|
@@ -13,6 +13,9 @@ from rich.console import Console
|
|
|
13
13
|
|
|
14
14
|
from griptape_nodes.retained_mode.events.base_events import ResultPayload
|
|
15
15
|
from griptape_nodes.retained_mode.events.os_events import (
|
|
16
|
+
CreateFileRequest,
|
|
17
|
+
CreateFileResultFailure,
|
|
18
|
+
CreateFileResultSuccess,
|
|
16
19
|
FileSystemEntry,
|
|
17
20
|
ListDirectoryRequest,
|
|
18
21
|
ListDirectoryResultFailure,
|
|
@@ -23,6 +26,9 @@ from griptape_nodes.retained_mode.events.os_events import (
|
|
|
23
26
|
ReadFileRequest,
|
|
24
27
|
ReadFileResultFailure,
|
|
25
28
|
ReadFileResultSuccess,
|
|
29
|
+
RenameFileRequest,
|
|
30
|
+
RenameFileResultFailure,
|
|
31
|
+
RenameFileResultSuccess,
|
|
26
32
|
)
|
|
27
33
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes, logger
|
|
28
34
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
@@ -59,6 +65,14 @@ class OSManager:
|
|
|
59
65
|
request_type=ReadFileRequest, callback=self.on_read_file_request
|
|
60
66
|
)
|
|
61
67
|
|
|
68
|
+
event_manager.assign_manager_to_request_type(
|
|
69
|
+
request_type=CreateFileRequest, callback=self.on_create_file_request
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
event_manager.assign_manager_to_request_type(
|
|
73
|
+
request_type=RenameFileRequest, callback=self.on_rename_file_request
|
|
74
|
+
)
|
|
75
|
+
|
|
62
76
|
def _get_workspace_path(self) -> Path:
|
|
63
77
|
"""Get the workspace path from config."""
|
|
64
78
|
return GriptapeNodes.ConfigManager().workspace_path
|
|
@@ -235,7 +249,7 @@ class OSManager:
|
|
|
235
249
|
logger.error(msg)
|
|
236
250
|
return OpenAssociatedFileResultFailure()
|
|
237
251
|
|
|
238
|
-
# Sanitize and validate the file
|
|
252
|
+
# Sanitize and validate the path (file or directory)
|
|
239
253
|
try:
|
|
240
254
|
# Resolve the path (no workspace fallback for open requests)
|
|
241
255
|
path = self._resolve_file_path(file_path_str, workspace_only=False)
|
|
@@ -244,12 +258,12 @@ class OSManager:
|
|
|
244
258
|
logger.info(details)
|
|
245
259
|
return OpenAssociatedFileResultFailure()
|
|
246
260
|
|
|
247
|
-
if not path.exists()
|
|
248
|
-
details = f"
|
|
261
|
+
if not path.exists():
|
|
262
|
+
details = f"Path does not exist: '{path}'"
|
|
249
263
|
logger.info(details)
|
|
250
264
|
return OpenAssociatedFileResultFailure()
|
|
251
265
|
|
|
252
|
-
logger.info("Attempting to open: %s on platform: %s", path, sys.platform)
|
|
266
|
+
logger.info("Attempting to open path: %s on platform: %s", path, sys.platform)
|
|
253
267
|
|
|
254
268
|
try:
|
|
255
269
|
platform_name = sys.platform
|
|
@@ -257,7 +271,7 @@ class OSManager:
|
|
|
257
271
|
# Linter complains but this is the recommended way on Windows
|
|
258
272
|
# We can ignore this warning as we've validated the path
|
|
259
273
|
os.startfile(str(path)) # noqa: S606 # pyright: ignore[reportAttributeAccessIssue]
|
|
260
|
-
logger.info("
|
|
274
|
+
logger.info("Opened path on Windows: %s", path)
|
|
261
275
|
elif self.is_mac():
|
|
262
276
|
# On macOS, open should be in a standard location
|
|
263
277
|
subprocess.run( # noqa: S603
|
|
@@ -266,7 +280,7 @@ class OSManager:
|
|
|
266
280
|
capture_output=True,
|
|
267
281
|
text=True,
|
|
268
282
|
)
|
|
269
|
-
logger.info("
|
|
283
|
+
logger.info("Opened path on macOS: %s", path)
|
|
270
284
|
elif self.is_linux():
|
|
271
285
|
# Use full path to xdg-open to satisfy linter
|
|
272
286
|
# Common locations for xdg-open:
|
|
@@ -283,7 +297,7 @@ class OSManager:
|
|
|
283
297
|
capture_output=True,
|
|
284
298
|
text=True,
|
|
285
299
|
)
|
|
286
|
-
logger.info("
|
|
300
|
+
logger.info("Opened path on Linux: %s", path)
|
|
287
301
|
else:
|
|
288
302
|
details = f"Unsupported platform: '{platform_name}'"
|
|
289
303
|
logger.info(details)
|
|
@@ -299,9 +313,24 @@ class OSManager:
|
|
|
299
313
|
)
|
|
300
314
|
return OpenAssociatedFileResultFailure()
|
|
301
315
|
except Exception as e:
|
|
302
|
-
logger.error("Exception occurred when trying to open
|
|
316
|
+
logger.error("Exception occurred when trying to open path: %s", type(e).__name__)
|
|
303
317
|
return OpenAssociatedFileResultFailure()
|
|
304
318
|
|
|
319
|
+
def _detect_mime_type(self, file_path: Path) -> str | None:
|
|
320
|
+
"""Detect MIME type for a file. Returns None for directories or if detection fails."""
|
|
321
|
+
if file_path.is_dir():
|
|
322
|
+
return None
|
|
323
|
+
|
|
324
|
+
try:
|
|
325
|
+
mime_type, _ = mimetypes.guess_type(str(file_path), strict=True)
|
|
326
|
+
if mime_type is None:
|
|
327
|
+
mime_type = "text/plain"
|
|
328
|
+
return mime_type # noqa: TRY300
|
|
329
|
+
except Exception as e:
|
|
330
|
+
msg = f"MIME type detection failed for {file_path}: {e}"
|
|
331
|
+
logger.warning(msg)
|
|
332
|
+
return "text/plain"
|
|
333
|
+
|
|
305
334
|
def on_list_directory_request(self, request: ListDirectoryRequest) -> ResultPayload: # noqa: C901, PLR0911
|
|
306
335
|
"""Handle a request to list directory contents."""
|
|
307
336
|
try:
|
|
@@ -345,6 +374,7 @@ class OSManager:
|
|
|
345
374
|
stat = entry.stat()
|
|
346
375
|
# Get path relative to workspace if within workspace
|
|
347
376
|
is_entry_in_workspace, entry_path = self._validate_workspace_path(entry)
|
|
377
|
+
mime_type = self._detect_mime_type(entry)
|
|
348
378
|
entries.append(
|
|
349
379
|
FileSystemEntry(
|
|
350
380
|
name=entry.name,
|
|
@@ -352,6 +382,7 @@ class OSManager:
|
|
|
352
382
|
is_dir=entry.is_dir(),
|
|
353
383
|
size=stat.st_size,
|
|
354
384
|
modified_time=stat.st_mtime,
|
|
385
|
+
mime_type=mime_type,
|
|
355
386
|
)
|
|
356
387
|
)
|
|
357
388
|
except (OSError, PermissionError) as e:
|
|
@@ -703,3 +734,97 @@ class OSManager:
|
|
|
703
734
|
logger.error("Attempted to clean up old files from %s, but no files could be deleted.")
|
|
704
735
|
|
|
705
736
|
return removed_count > 0
|
|
737
|
+
|
|
738
|
+
def on_create_file_request(self, request: CreateFileRequest) -> ResultPayload:
|
|
739
|
+
"""Handle a request to create a file or directory."""
|
|
740
|
+
try:
|
|
741
|
+
# Get the full path using the new method
|
|
742
|
+
full_path_str = request.get_full_path()
|
|
743
|
+
|
|
744
|
+
# Determine if path is absolute (not constrained to workspace)
|
|
745
|
+
is_absolute = Path(full_path_str).is_absolute()
|
|
746
|
+
|
|
747
|
+
# If workspace_only is True and path is absolute, it's outside workspace
|
|
748
|
+
if request.workspace_only and is_absolute:
|
|
749
|
+
msg = f"Absolute path is outside workspace: {full_path_str}"
|
|
750
|
+
logger.error(msg)
|
|
751
|
+
return CreateFileResultFailure()
|
|
752
|
+
|
|
753
|
+
# Resolve path - if absolute, use as-is; if relative, align to workspace
|
|
754
|
+
if is_absolute:
|
|
755
|
+
file_path = Path(full_path_str).resolve()
|
|
756
|
+
else:
|
|
757
|
+
file_path = (self._get_workspace_path() / full_path_str).resolve()
|
|
758
|
+
|
|
759
|
+
# Check if it already exists - warn but treat as success
|
|
760
|
+
if file_path.exists():
|
|
761
|
+
msg = f"Path already exists: {file_path}"
|
|
762
|
+
logger.warning(msg)
|
|
763
|
+
return CreateFileResultSuccess(created_path=str(file_path))
|
|
764
|
+
|
|
765
|
+
# Create parent directories if needed
|
|
766
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
767
|
+
|
|
768
|
+
if request.is_directory:
|
|
769
|
+
file_path.mkdir()
|
|
770
|
+
logger.info("Created directory: %s", file_path)
|
|
771
|
+
# Create file with optional content
|
|
772
|
+
elif request.content is not None:
|
|
773
|
+
with file_path.open("w", encoding=request.encoding) as f:
|
|
774
|
+
f.write(request.content)
|
|
775
|
+
logger.info("Created file with content: %s", file_path)
|
|
776
|
+
else:
|
|
777
|
+
file_path.touch()
|
|
778
|
+
logger.info("Created empty file: %s", file_path)
|
|
779
|
+
|
|
780
|
+
return CreateFileResultSuccess(created_path=str(file_path))
|
|
781
|
+
|
|
782
|
+
except Exception as e:
|
|
783
|
+
path_info = request.get_full_path() if hasattr(request, "get_full_path") else str(request.path)
|
|
784
|
+
msg = f"Failed to create {'directory' if request.is_directory else 'file'} at {path_info}: {e}"
|
|
785
|
+
logger.error(msg)
|
|
786
|
+
return CreateFileResultFailure()
|
|
787
|
+
|
|
788
|
+
def on_rename_file_request(self, request: RenameFileRequest) -> ResultPayload:
|
|
789
|
+
"""Handle a request to rename a file or directory."""
|
|
790
|
+
try:
|
|
791
|
+
# Resolve and validate old path
|
|
792
|
+
old_path = self._resolve_file_path(request.old_path, workspace_only=request.workspace_only is True)
|
|
793
|
+
|
|
794
|
+
# Resolve and validate new path
|
|
795
|
+
new_path = self._resolve_file_path(request.new_path, workspace_only=request.workspace_only is True)
|
|
796
|
+
|
|
797
|
+
# Check if old path exists
|
|
798
|
+
if not old_path.exists():
|
|
799
|
+
msg = f"Source path does not exist: {old_path}"
|
|
800
|
+
logger.error(msg)
|
|
801
|
+
return RenameFileResultFailure()
|
|
802
|
+
|
|
803
|
+
# Check if new path already exists
|
|
804
|
+
if new_path.exists():
|
|
805
|
+
msg = f"Destination path already exists: {new_path}"
|
|
806
|
+
logger.error(msg)
|
|
807
|
+
return RenameFileResultFailure()
|
|
808
|
+
|
|
809
|
+
# Check workspace constraints for both paths
|
|
810
|
+
is_old_in_workspace, _ = self._validate_workspace_path(old_path)
|
|
811
|
+
is_new_in_workspace, _ = self._validate_workspace_path(new_path)
|
|
812
|
+
|
|
813
|
+
if request.workspace_only and (not is_old_in_workspace or not is_new_in_workspace):
|
|
814
|
+
msg = f"One or both paths are outside workspace: {old_path} -> {new_path}"
|
|
815
|
+
logger.error(msg)
|
|
816
|
+
return RenameFileResultFailure()
|
|
817
|
+
|
|
818
|
+
# Create parent directories for new path if needed
|
|
819
|
+
new_path.parent.mkdir(parents=True, exist_ok=True)
|
|
820
|
+
|
|
821
|
+
# Perform the rename operation
|
|
822
|
+
old_path.rename(new_path)
|
|
823
|
+
logger.info("Renamed: %s -> %s", old_path, new_path)
|
|
824
|
+
|
|
825
|
+
return RenameFileResultSuccess(old_path=str(old_path), new_path=str(new_path))
|
|
826
|
+
|
|
827
|
+
except Exception as e:
|
|
828
|
+
msg = f"Failed to rename {request.old_path} to {request.new_path}: {e}"
|
|
829
|
+
logger.error(msg)
|
|
830
|
+
return RenameFileResultFailure()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -91,6 +91,7 @@ if TYPE_CHECKING:
|
|
|
91
91
|
from griptape_nodes.exe_types.core_types import Parameter
|
|
92
92
|
from griptape_nodes.node_library.library_registry import LibraryNameAndVersion
|
|
93
93
|
from griptape_nodes.retained_mode.events.base_events import ResultPayload
|
|
94
|
+
from griptape_nodes.retained_mode.events.node_events import SetLockNodeStateRequest
|
|
94
95
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
95
96
|
|
|
96
97
|
|
|
@@ -1064,6 +1065,7 @@ class WorkflowManager:
|
|
|
1064
1065
|
or len(serialized_flow_commands.serialized_connections) > 0
|
|
1065
1066
|
or len(serialized_flow_commands.set_parameter_value_commands) > 0
|
|
1066
1067
|
or len(serialized_flow_commands.sub_flows_commands) > 0
|
|
1068
|
+
or len(serialized_flow_commands.set_lock_commands_per_node) > 0
|
|
1067
1069
|
)
|
|
1068
1070
|
|
|
1069
1071
|
if not is_referenced_workflow and has_content_to_serialize:
|
|
@@ -1110,6 +1112,7 @@ class WorkflowManager:
|
|
|
1110
1112
|
# Now generate all the set parameter value code and add it to the flow context.
|
|
1111
1113
|
set_parameter_value_asts = self._generate_set_parameter_value_code(
|
|
1112
1114
|
set_parameter_value_commands=serialized_flow_commands.set_parameter_value_commands,
|
|
1115
|
+
lock_commands=serialized_flow_commands.set_lock_commands_per_node,
|
|
1113
1116
|
node_uuid_to_node_variable_name=node_uuid_to_node_variable_name,
|
|
1114
1117
|
unique_values_dict_name="top_level_unique_values_dict",
|
|
1115
1118
|
import_recorder=import_recorder,
|
|
@@ -2503,6 +2506,7 @@ class WorkflowManager:
|
|
|
2503
2506
|
set_parameter_value_commands: dict[
|
|
2504
2507
|
SerializedNodeCommands.NodeUUID, list[SerializedNodeCommands.IndirectSetParameterValueCommand]
|
|
2505
2508
|
],
|
|
2509
|
+
lock_commands: dict[SerializedNodeCommands.NodeUUID, SetLockNodeStateRequest],
|
|
2506
2510
|
node_uuid_to_node_variable_name: dict[SerializedNodeCommands.NodeUUID, str],
|
|
2507
2511
|
unique_values_dict_name: str,
|
|
2508
2512
|
import_recorder: ImportRecorder,
|
|
@@ -2510,9 +2514,14 @@ class WorkflowManager:
|
|
|
2510
2514
|
parameter_value_asts = []
|
|
2511
2515
|
for node_uuid, indirect_set_parameter_value_commands in set_parameter_value_commands.items():
|
|
2512
2516
|
node_variable_name = node_uuid_to_node_variable_name[node_uuid]
|
|
2517
|
+
lock_node_command = lock_commands.get(node_uuid)
|
|
2513
2518
|
parameter_value_asts.extend(
|
|
2514
2519
|
self._generate_set_parameter_value_for_node(
|
|
2515
|
-
node_variable_name,
|
|
2520
|
+
node_variable_name,
|
|
2521
|
+
indirect_set_parameter_value_commands,
|
|
2522
|
+
unique_values_dict_name,
|
|
2523
|
+
import_recorder,
|
|
2524
|
+
lock_node_command,
|
|
2516
2525
|
)
|
|
2517
2526
|
)
|
|
2518
2527
|
return parameter_value_asts
|
|
@@ -2523,13 +2532,15 @@ class WorkflowManager:
|
|
|
2523
2532
|
indirect_set_parameter_value_commands: list[SerializedNodeCommands.IndirectSetParameterValueCommand],
|
|
2524
2533
|
unique_values_dict_name: str,
|
|
2525
2534
|
import_recorder: ImportRecorder,
|
|
2535
|
+
lock_node_command: SetLockNodeStateRequest | None = None,
|
|
2526
2536
|
) -> list[ast.stmt]:
|
|
2527
|
-
if not indirect_set_parameter_value_commands:
|
|
2537
|
+
if not indirect_set_parameter_value_commands and lock_node_command is None:
|
|
2528
2538
|
return []
|
|
2529
2539
|
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2540
|
+
if indirect_set_parameter_value_commands:
|
|
2541
|
+
import_recorder.add_from_import(
|
|
2542
|
+
"griptape_nodes.retained_mode.events.parameter_events", "SetParameterValueRequest"
|
|
2543
|
+
)
|
|
2533
2544
|
|
|
2534
2545
|
set_parameter_value_asts = []
|
|
2535
2546
|
with_node_context = ast.With(
|
|
@@ -2613,6 +2624,44 @@ class WorkflowManager:
|
|
|
2613
2624
|
)
|
|
2614
2625
|
with_node_context.body.append(set_parameter_value_request_call)
|
|
2615
2626
|
|
|
2627
|
+
# Add lock command as the LAST command in the with context
|
|
2628
|
+
if lock_node_command is not None:
|
|
2629
|
+
import_recorder.add_from_import(
|
|
2630
|
+
"griptape_nodes.retained_mode.events.node_events", "SetLockNodeStateRequest"
|
|
2631
|
+
)
|
|
2632
|
+
|
|
2633
|
+
lock_node_call_ast = ast.Expr(
|
|
2634
|
+
value=ast.Call(
|
|
2635
|
+
func=ast.Attribute(
|
|
2636
|
+
value=ast.Name(id="GriptapeNodes", ctx=ast.Load(), lineno=1, col_offset=0),
|
|
2637
|
+
attr="handle_request",
|
|
2638
|
+
ctx=ast.Load(),
|
|
2639
|
+
lineno=1,
|
|
2640
|
+
col_offset=0,
|
|
2641
|
+
),
|
|
2642
|
+
args=[
|
|
2643
|
+
ast.Call(
|
|
2644
|
+
func=ast.Name(id="SetLockNodeStateRequest", ctx=ast.Load(), lineno=1, col_offset=0),
|
|
2645
|
+
args=[],
|
|
2646
|
+
keywords=[
|
|
2647
|
+
ast.keyword(arg="node_name", value=ast.Constant(value=None, lineno=1, col_offset=0)),
|
|
2648
|
+
ast.keyword(
|
|
2649
|
+
arg="lock", value=ast.Constant(value=lock_node_command.lock, lineno=1, col_offset=0)
|
|
2650
|
+
),
|
|
2651
|
+
],
|
|
2652
|
+
lineno=1,
|
|
2653
|
+
col_offset=0,
|
|
2654
|
+
)
|
|
2655
|
+
],
|
|
2656
|
+
keywords=[],
|
|
2657
|
+
lineno=1,
|
|
2658
|
+
col_offset=0,
|
|
2659
|
+
),
|
|
2660
|
+
lineno=1,
|
|
2661
|
+
col_offset=0,
|
|
2662
|
+
)
|
|
2663
|
+
with_node_context.body.append(lock_node_call_ast)
|
|
2664
|
+
|
|
2616
2665
|
set_parameter_value_asts.append(with_node_context)
|
|
2617
2666
|
return set_parameter_value_asts
|
|
2618
2667
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
griptape_nodes/traits/button.py
CHANGED
|
File without changes
|
griptape_nodes/traits/clamp.py
CHANGED
|
File without changes
|
griptape_nodes/traits/compare.py
CHANGED
|
File without changes
|
|
File without changes
|
|
@@ -18,6 +18,8 @@ class FileSystemPicker(Trait):
|
|
|
18
18
|
min_file_size: int | None = None
|
|
19
19
|
workspace_only: bool = True
|
|
20
20
|
initial_path: str | None = None
|
|
21
|
+
allow_create: bool = False
|
|
22
|
+
allow_rename: bool = False
|
|
21
23
|
element_id: str = field(default_factory=lambda: "FileSystemPicker")
|
|
22
24
|
|
|
23
25
|
def __init__( # noqa: PLR0913
|
|
@@ -34,6 +36,8 @@ class FileSystemPicker(Trait):
|
|
|
34
36
|
min_file_size: int | None = None,
|
|
35
37
|
workspace_only: bool = True,
|
|
36
38
|
initial_path: str | None = None,
|
|
39
|
+
allow_create: bool = False,
|
|
40
|
+
allow_rename: bool = False,
|
|
37
41
|
) -> None:
|
|
38
42
|
super().__init__()
|
|
39
43
|
self.allow_files = allow_files
|
|
@@ -47,6 +51,8 @@ class FileSystemPicker(Trait):
|
|
|
47
51
|
self.min_file_size = min_file_size
|
|
48
52
|
self.workspace_only = workspace_only
|
|
49
53
|
self.initial_path = initial_path
|
|
54
|
+
self.allow_create = allow_create
|
|
55
|
+
self.allow_rename = allow_rename
|
|
50
56
|
|
|
51
57
|
@classmethod
|
|
52
58
|
def get_trait_keys(cls) -> list[str]:
|
|
@@ -59,6 +65,8 @@ class FileSystemPicker(Trait):
|
|
|
59
65
|
"allowDirectories": self.allow_directories,
|
|
60
66
|
"multiple": self.multiple,
|
|
61
67
|
"workspaceOnly": self.workspace_only,
|
|
68
|
+
"allowCreate": self.allow_create,
|
|
69
|
+
"allowRename": self.allow_rename,
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
# Add file types/extensions
|
|
@@ -94,6 +102,16 @@ class FileSystemPicker(Trait):
|
|
|
94
102
|
msg = "At least one of allow_files or allow_directories must be True"
|
|
95
103
|
raise ValueError(msg)
|
|
96
104
|
|
|
105
|
+
# Validate that creation is only allowed when appropriate selection types are enabled
|
|
106
|
+
if self.allow_create and not self.allow_files and not self.allow_directories:
|
|
107
|
+
msg = "allow_create requires at least one of allow_files or allow_directories to be True"
|
|
108
|
+
raise ValueError(msg)
|
|
109
|
+
|
|
110
|
+
# Validate that rename is only allowed when appropriate selection types are enabled
|
|
111
|
+
if self.allow_rename and not self.allow_files and not self.allow_directories:
|
|
112
|
+
msg = "allow_rename requires at least one of allow_files or allow_directories to be True"
|
|
113
|
+
raise ValueError(msg)
|
|
114
|
+
|
|
97
115
|
# Validate file size limits
|
|
98
116
|
if (
|
|
99
117
|
self.max_file_size is not None
|
griptape_nodes/traits/minmax.py
CHANGED
|
File without changes
|
griptape_nodes/traits/options.py
CHANGED
|
File without changes
|
griptape_nodes/traits/slider.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
griptape_nodes/utils/__init__.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Version utilities for Griptape Nodes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib.metadata
|
|
6
|
+
import json
|
|
7
|
+
from typing import Literal
|
|
8
|
+
|
|
9
|
+
engine_version = importlib.metadata.version("griptape_nodes")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_current_version() -> str:
|
|
13
|
+
"""Returns the current version of the Griptape Nodes package."""
|
|
14
|
+
return f"v{engine_version}"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_install_source() -> tuple[Literal["git", "file", "pypi"], str | None]:
|
|
18
|
+
"""Determines the install source of the Griptape Nodes package.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
tuple: A tuple containing the install source and commit ID (if applicable).
|
|
22
|
+
"""
|
|
23
|
+
dist = importlib.metadata.distribution("griptape_nodes")
|
|
24
|
+
direct_url_text = dist.read_text("direct_url.json")
|
|
25
|
+
# installing from pypi doesn't have a direct_url.json file
|
|
26
|
+
if direct_url_text is None:
|
|
27
|
+
return "pypi", None
|
|
28
|
+
|
|
29
|
+
direct_url_info = json.loads(direct_url_text)
|
|
30
|
+
url = direct_url_info.get("url")
|
|
31
|
+
if url and url.startswith("file://"):
|
|
32
|
+
return "file", None
|
|
33
|
+
if "vcs_info" in direct_url_info:
|
|
34
|
+
return "git", direct_url_info["vcs_info"].get("commit_id")[:7]
|
|
35
|
+
# Fall back to pypi if no other source is found
|
|
36
|
+
return "pypi", None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_complete_version_string() -> str:
|
|
40
|
+
"""Returns the complete version string including install source and commit ID.
|
|
41
|
+
|
|
42
|
+
Format: v1.2.3 (source) or v1.2.3 (source - commit_id)
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Complete version string with source and commit info.
|
|
46
|
+
"""
|
|
47
|
+
version = get_current_version()
|
|
48
|
+
source, commit_id = get_install_source()
|
|
49
|
+
if commit_id is None:
|
|
50
|
+
return f"{version} ({source})"
|
|
51
|
+
return f"{version} ({source} - {commit_id})"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|