griptape-nodes 0.42.0__py3-none-any.whl → 0.43.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/__init__.py +0 -0
- griptape_nodes/app/.python-version +0 -0
- griptape_nodes/app/__init__.py +1 -6
- griptape_nodes/app/api.py +199 -0
- griptape_nodes/app/app.py +140 -225
- griptape_nodes/app/watch.py +1 -1
- griptape_nodes/bootstrap/__init__.py +0 -0
- griptape_nodes/bootstrap/bootstrap_script.py +0 -0
- griptape_nodes/bootstrap/register_libraries_script.py +0 -0
- griptape_nodes/bootstrap/structure_config.yaml +0 -0
- griptape_nodes/bootstrap/workflow_executors/__init__.py +0 -0
- griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +0 -0
- griptape_nodes/bootstrap/workflow_executors/workflow_executor.py +0 -0
- griptape_nodes/bootstrap/workflow_runners/__init__.py +0 -0
- griptape_nodes/bootstrap/workflow_runners/bootstrap_workflow_runner.py +0 -0
- griptape_nodes/bootstrap/workflow_runners/local_workflow_runner.py +0 -0
- griptape_nodes/bootstrap/workflow_runners/subprocess_workflow_runner.py +6 -2
- griptape_nodes/bootstrap/workflow_runners/workflow_runner.py +0 -0
- griptape_nodes/drivers/__init__.py +0 -0
- griptape_nodes/drivers/storage/__init__.py +0 -0
- griptape_nodes/drivers/storage/base_storage_driver.py +0 -0
- griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +0 -0
- griptape_nodes/drivers/storage/local_storage_driver.py +2 -1
- 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 +0 -0
- griptape_nodes/exe_types/flow.py +0 -0
- griptape_nodes/exe_types/node_types.py +17 -1
- griptape_nodes/exe_types/type_validator.py +0 -0
- griptape_nodes/machines/__init__.py +0 -0
- griptape_nodes/machines/control_flow.py +41 -12
- griptape_nodes/machines/fsm.py +16 -2
- griptape_nodes/machines/node_resolution.py +0 -0
- griptape_nodes/mcp_server/__init__.py +1 -0
- griptape_nodes/mcp_server/server.py +126 -0
- griptape_nodes/mcp_server/ws_request_manager.py +268 -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 +1 -1
- 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 +6 -2
- griptape_nodes/retained_mode/events/arbitrary_python_events.py +0 -0
- griptape_nodes/retained_mode/events/base_events.py +6 -6
- 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 +0 -0
- griptape_nodes/retained_mode/events/generate_request_payload_schemas.py +0 -0
- griptape_nodes/retained_mode/events/library_events.py +2 -2
- griptape_nodes/retained_mode/events/logger_events.py +0 -0
- griptape_nodes/retained_mode/events/node_events.py +0 -0
- griptape_nodes/retained_mode/events/object_events.py +0 -0
- griptape_nodes/retained_mode/events/os_events.py +104 -2
- 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 +43 -40
- griptape_nodes/retained_mode/managers/__init__.py +0 -0
- griptape_nodes/retained_mode/managers/agent_manager.py +48 -22
- griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +0 -0
- griptape_nodes/retained_mode/managers/config_manager.py +0 -0
- 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 +2 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/__init__.py +45 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/data_models.py +191 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +346 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_fsm.py +439 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/__init__.py +17 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/base.py +82 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/github.py +116 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +352 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/package.py +104 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/sandbox.py +155 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance.py +18 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_status.py +12 -0
- griptape_nodes/retained_mode/managers/library_manager.py +144 -39
- griptape_nodes/retained_mode/managers/node_manager.py +86 -72
- 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 +517 -12
- 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 +2 -2
- griptape_nodes/retained_mode/managers/workflow_manager.py +199 -2
- 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 +127 -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 +2 -2
- 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 +128 -0
- griptape_nodes/utils/metaclasses.py +0 -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 +5 -5
- griptape_nodes-0.43.1.dist-info/METADATA +90 -0
- griptape_nodes-0.43.1.dist-info/RECORD +129 -0
- griptape_nodes-0.43.1.dist-info/WHEEL +4 -0
- {griptape_nodes-0.42.0.dist-info → griptape_nodes-0.43.1.dist-info}/entry_points.txt +1 -0
- griptape_nodes/app/app_sessions.py +0 -554
- griptape_nodes-0.42.0.dist-info/METADATA +0 -78
- griptape_nodes-0.42.0.dist-info/RECORD +0 -113
- griptape_nodes-0.42.0.dist-info/WHEEL +0 -4
- griptape_nodes-0.42.0.dist-info/licenses/LICENSE +0 -201
|
@@ -9,7 +9,6 @@ import subprocess
|
|
|
9
9
|
import sys
|
|
10
10
|
import sysconfig
|
|
11
11
|
from dataclasses import dataclass, field
|
|
12
|
-
from enum import StrEnum
|
|
13
12
|
from importlib.resources import files
|
|
14
13
|
from pathlib import Path
|
|
15
14
|
from typing import TYPE_CHECKING, cast
|
|
@@ -17,6 +16,7 @@ from typing import TYPE_CHECKING, cast
|
|
|
17
16
|
import uv
|
|
18
17
|
from packaging.requirements import InvalidRequirement, Requirement
|
|
19
18
|
from pydantic import ValidationError
|
|
19
|
+
from rich.align import Align
|
|
20
20
|
from rich.box import HEAVY_EDGE
|
|
21
21
|
from rich.console import Console
|
|
22
22
|
from rich.panel import Panel
|
|
@@ -90,6 +90,11 @@ from griptape_nodes.retained_mode.events.library_events import (
|
|
|
90
90
|
from griptape_nodes.retained_mode.events.object_events import ClearAllObjectStateRequest
|
|
91
91
|
from griptape_nodes.retained_mode.events.payload_registry import PayloadRegistry
|
|
92
92
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
93
|
+
from griptape_nodes.retained_mode.managers.library_lifecycle.library_directory import LibraryDirectory
|
|
94
|
+
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.local_file import (
|
|
95
|
+
LibraryProvenanceLocalFile,
|
|
96
|
+
)
|
|
97
|
+
from griptape_nodes.retained_mode.managers.library_lifecycle.library_status import LibraryStatus
|
|
93
98
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
94
99
|
|
|
95
100
|
if TYPE_CHECKING:
|
|
@@ -101,6 +106,7 @@ if TYPE_CHECKING:
|
|
|
101
106
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
102
107
|
|
|
103
108
|
logger = logging.getLogger("griptape_nodes")
|
|
109
|
+
console = Console()
|
|
104
110
|
|
|
105
111
|
|
|
106
112
|
def _find_griptape_uv_bin() -> str:
|
|
@@ -121,14 +127,6 @@ def _find_griptape_uv_bin() -> str:
|
|
|
121
127
|
class LibraryManager:
|
|
122
128
|
SANDBOX_LIBRARY_NAME = "Sandbox Library"
|
|
123
129
|
|
|
124
|
-
class LibraryStatus(StrEnum):
|
|
125
|
-
"""Status of the library that was attempted to be loaded."""
|
|
126
|
-
|
|
127
|
-
GOOD = "GOOD" # No errors detected during loading. Registered.
|
|
128
|
-
FLAWED = "FLAWED" # Some errors detected, but recoverable. Registered.
|
|
129
|
-
UNUSABLE = "UNUSABLE" # Errors detected and not recoverable. Not registered.
|
|
130
|
-
MISSING = "MISSING" # File not found. Not registered.
|
|
131
|
-
|
|
132
130
|
@dataclass
|
|
133
131
|
class LibraryInfo:
|
|
134
132
|
"""Information about a library that was attempted to be loaded.
|
|
@@ -136,7 +134,7 @@ class LibraryManager:
|
|
|
136
134
|
Includes the status of the library, the file path, and any problems encountered during loading.
|
|
137
135
|
"""
|
|
138
136
|
|
|
139
|
-
status:
|
|
137
|
+
status: LibraryStatus
|
|
140
138
|
library_path: str
|
|
141
139
|
library_name: str | None = None
|
|
142
140
|
library_version: str | None = None
|
|
@@ -176,6 +174,8 @@ class LibraryManager:
|
|
|
176
174
|
self._stable_to_dynamic_module_mapping = {}
|
|
177
175
|
self._library_to_stable_modules = {}
|
|
178
176
|
self._library_event_handler_mappings: dict[type[Payload], dict[str, LibraryManager.RegisteredEventHandler]] = {}
|
|
177
|
+
# LibraryDirectory owns the FSMs and manages library lifecycle
|
|
178
|
+
self._library_directory = LibraryDirectory()
|
|
179
179
|
|
|
180
180
|
event_manager.assign_manager_to_request_type(
|
|
181
181
|
ListRegisteredLibrariesRequest, self.on_list_registered_libraries_request
|
|
@@ -254,10 +254,10 @@ class LibraryManager:
|
|
|
254
254
|
|
|
255
255
|
# Status emojis mapping
|
|
256
256
|
status_emoji = {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
257
|
+
LibraryStatus.GOOD: "✅",
|
|
258
|
+
LibraryStatus.FLAWED: "🟡",
|
|
259
|
+
LibraryStatus.UNUSABLE: "❌",
|
|
260
|
+
LibraryStatus.MISSING: "❓",
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
# Add rows for each library info
|
|
@@ -408,7 +408,7 @@ class LibraryManager:
|
|
|
408
408
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
409
409
|
library_path=file_path,
|
|
410
410
|
library_name=None,
|
|
411
|
-
status=
|
|
411
|
+
status=LibraryStatus.MISSING,
|
|
412
412
|
problems=[
|
|
413
413
|
"Library could not be found at the file path specified. It will be removed from the configuration."
|
|
414
414
|
],
|
|
@@ -424,7 +424,7 @@ class LibraryManager:
|
|
|
424
424
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
425
425
|
library_path=file_path,
|
|
426
426
|
library_name=None,
|
|
427
|
-
status=
|
|
427
|
+
status=LibraryStatus.UNUSABLE,
|
|
428
428
|
problems=["Library file not formatted as proper JSON."],
|
|
429
429
|
)
|
|
430
430
|
except Exception as err:
|
|
@@ -433,7 +433,7 @@ class LibraryManager:
|
|
|
433
433
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
434
434
|
library_path=file_path,
|
|
435
435
|
library_name=None,
|
|
436
|
-
status=
|
|
436
|
+
status=LibraryStatus.UNUSABLE,
|
|
437
437
|
problems=[f"Exception occurred when attempting to load the library: {err}."],
|
|
438
438
|
)
|
|
439
439
|
|
|
@@ -457,7 +457,7 @@ class LibraryManager:
|
|
|
457
457
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
458
458
|
library_path=file_path,
|
|
459
459
|
library_name=library_name,
|
|
460
|
-
status=
|
|
460
|
+
status=LibraryStatus.UNUSABLE,
|
|
461
461
|
problems=problems,
|
|
462
462
|
)
|
|
463
463
|
except Exception as err:
|
|
@@ -466,7 +466,7 @@ class LibraryManager:
|
|
|
466
466
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
467
467
|
library_path=file_path,
|
|
468
468
|
library_name=library_name,
|
|
469
|
-
status=
|
|
469
|
+
status=LibraryStatus.UNUSABLE,
|
|
470
470
|
problems=[f"Library file did not match the library schema specified due to: {err}"],
|
|
471
471
|
)
|
|
472
472
|
|
|
@@ -540,7 +540,7 @@ class LibraryManager:
|
|
|
540
540
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
541
541
|
library_path=sandbox_library_dir_as_posix,
|
|
542
542
|
library_name=LibraryManager.SANDBOX_LIBRARY_NAME,
|
|
543
|
-
status=
|
|
543
|
+
status=LibraryStatus.MISSING,
|
|
544
544
|
problems=["Sandbox directory does not exist."],
|
|
545
545
|
)
|
|
546
546
|
|
|
@@ -595,7 +595,7 @@ class LibraryManager:
|
|
|
595
595
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
596
596
|
library_path=sandbox_library_dir_as_posix,
|
|
597
597
|
library_name=LibraryManager.SANDBOX_LIBRARY_NAME,
|
|
598
|
-
status=
|
|
598
|
+
status=LibraryStatus.UNUSABLE,
|
|
599
599
|
problems=["Could not get engine version for sandbox library generation."],
|
|
600
600
|
)
|
|
601
601
|
|
|
@@ -679,7 +679,7 @@ class LibraryManager:
|
|
|
679
679
|
self._library_file_path_to_info[file_path] = LibraryManager.LibraryInfo(
|
|
680
680
|
library_path=file_path,
|
|
681
681
|
library_name=None,
|
|
682
|
-
status=
|
|
682
|
+
status=LibraryStatus.MISSING,
|
|
683
683
|
problems=[
|
|
684
684
|
"Library could not be found at the file path specified. It will be removed from the configuration."
|
|
685
685
|
],
|
|
@@ -713,7 +713,7 @@ class LibraryManager:
|
|
|
713
713
|
self._library_file_path_to_info[file_path] = LibraryManager.LibraryInfo(
|
|
714
714
|
library_path=file_path,
|
|
715
715
|
library_name=library_data.name,
|
|
716
|
-
status=
|
|
716
|
+
status=LibraryStatus.UNUSABLE,
|
|
717
717
|
problems=[
|
|
718
718
|
f"Library's version string '{library_data.metadata.library_version}' wasn't valid. Must be in major.minor.patch format."
|
|
719
719
|
],
|
|
@@ -740,7 +740,7 @@ class LibraryManager:
|
|
|
740
740
|
library_path=file_path,
|
|
741
741
|
library_name=library_data.name,
|
|
742
742
|
library_version=library_version,
|
|
743
|
-
status=
|
|
743
|
+
status=LibraryStatus.UNUSABLE,
|
|
744
744
|
problems=[
|
|
745
745
|
f"Failed to load Advanced Library module from '{library_data.advanced_library_path}': {err}"
|
|
746
746
|
],
|
|
@@ -764,7 +764,7 @@ class LibraryManager:
|
|
|
764
764
|
library_path=file_path,
|
|
765
765
|
library_name=library_data.name,
|
|
766
766
|
library_version=library_version,
|
|
767
|
-
status=
|
|
767
|
+
status=LibraryStatus.UNUSABLE,
|
|
768
768
|
problems=[
|
|
769
769
|
"Failed because a library with this name was already registered. Check the Settings to ensure duplicate libraries are not being loaded."
|
|
770
770
|
],
|
|
@@ -793,7 +793,7 @@ class LibraryManager:
|
|
|
793
793
|
library_path=file_path,
|
|
794
794
|
library_name=library_data.name,
|
|
795
795
|
library_version=library_version,
|
|
796
|
-
status=
|
|
796
|
+
status=LibraryStatus.UNUSABLE,
|
|
797
797
|
problems=[str(e)],
|
|
798
798
|
)
|
|
799
799
|
details = f"Attempted to load Library JSON file from '{json_path}'. Failed when creating the virtual environment: {e}."
|
|
@@ -815,7 +815,7 @@ class LibraryManager:
|
|
|
815
815
|
library_path=file_path,
|
|
816
816
|
library_name=library_data.name,
|
|
817
817
|
library_version=library_version,
|
|
818
|
-
status=
|
|
818
|
+
status=LibraryStatus.UNUSABLE,
|
|
819
819
|
problems=[
|
|
820
820
|
f"Insufficient disk space for dependencies (requires {min_space_gb} GB): {error_msg}"
|
|
821
821
|
],
|
|
@@ -856,7 +856,7 @@ class LibraryManager:
|
|
|
856
856
|
library_path=file_path,
|
|
857
857
|
library_name=library_data.name,
|
|
858
858
|
library_version=library_version,
|
|
859
|
-
status=
|
|
859
|
+
status=LibraryStatus.UNUSABLE,
|
|
860
860
|
problems=[f"Dependency installation failed: {error_details}"],
|
|
861
861
|
)
|
|
862
862
|
details = f"Attempted to load Library JSON file from '{json_path}'. Failed when installing dependencies: {error_details}"
|
|
@@ -888,7 +888,9 @@ class LibraryManager:
|
|
|
888
888
|
else:
|
|
889
889
|
# We had an existing category. Union our changes into it (not replacing anything that matched).
|
|
890
890
|
existing_category_contents = get_category_result.contents
|
|
891
|
-
existing_category_contents
|
|
891
|
+
existing_category_contents |= {
|
|
892
|
+
k: v for k, v in library_data_setting.contents.items() if k not in existing_category_contents
|
|
893
|
+
}
|
|
892
894
|
set_category_request = SetConfigCategoryRequest(
|
|
893
895
|
category=library_data_setting.category, contents=existing_category_contents
|
|
894
896
|
)
|
|
@@ -911,15 +913,15 @@ class LibraryManager:
|
|
|
911
913
|
self._library_file_path_to_info[file_path] = library_load_results
|
|
912
914
|
|
|
913
915
|
match library_load_results.status:
|
|
914
|
-
case
|
|
916
|
+
case LibraryStatus.GOOD:
|
|
915
917
|
details = f"Successfully loaded Library '{library_data.name}' from JSON file at {json_path}"
|
|
916
918
|
logger.info(details)
|
|
917
919
|
return RegisterLibraryFromFileResultSuccess(library_name=library_data.name)
|
|
918
|
-
case
|
|
920
|
+
case LibraryStatus.FLAWED:
|
|
919
921
|
details = f"Successfully loaded Library JSON file from '{json_path}', but one or more nodes failed to load. Check the log for more details."
|
|
920
922
|
logger.warning(details)
|
|
921
923
|
return RegisterLibraryFromFileResultSuccess(library_name=library_data.name)
|
|
922
|
-
case
|
|
924
|
+
case LibraryStatus.UNUSABLE:
|
|
923
925
|
details = f"Attempted to load Library JSON file from '{json_path}'. Failed because no nodes were loaded. Check the log for more details."
|
|
924
926
|
logger.error(details)
|
|
925
927
|
return RegisterLibraryFromFileResultFailure()
|
|
@@ -1501,6 +1503,8 @@ class LibraryManager:
|
|
|
1501
1503
|
return node_class
|
|
1502
1504
|
|
|
1503
1505
|
def load_all_libraries_from_config(self) -> None:
|
|
1506
|
+
# Comment out lines 1503-1545 and call the _load libraries from provenance system to test the other functionality.
|
|
1507
|
+
|
|
1504
1508
|
# Load metadata for all libraries to determine which ones can be safely loaded
|
|
1505
1509
|
metadata_request = LoadMetadataForAllLibrariesRequest()
|
|
1506
1510
|
metadata_result = self.load_metadata_for_all_libraries_request(metadata_request)
|
|
@@ -1589,6 +1593,107 @@ class LibraryManager:
|
|
|
1589
1593
|
# Go tell the Workflow Manager that it's turn is now.
|
|
1590
1594
|
GriptapeNodes.WorkflowManager().on_libraries_initialization_complete()
|
|
1591
1595
|
|
|
1596
|
+
# Print the engine ready message
|
|
1597
|
+
engine_version_request = GetEngineVersionRequest()
|
|
1598
|
+
engine_version_result = GriptapeNodes.get_instance().handle_engine_version_request(engine_version_request)
|
|
1599
|
+
if isinstance(engine_version_result, GetEngineVersionResultSuccess):
|
|
1600
|
+
engine_version = (
|
|
1601
|
+
f"v{engine_version_result.major}.{engine_version_result.minor}.{engine_version_result.patch}"
|
|
1602
|
+
)
|
|
1603
|
+
else:
|
|
1604
|
+
engine_version = "<UNKNOWN ENGINE VERSION>"
|
|
1605
|
+
|
|
1606
|
+
# Get current session ID
|
|
1607
|
+
session_id = GriptapeNodes.get_session_id()
|
|
1608
|
+
session_info = f" | Session: {session_id[:8]}..." if session_id else " | No Session"
|
|
1609
|
+
|
|
1610
|
+
nodes_app_url = os.getenv("GRIPTAPE_NODES_UI_BASE_URL", "https://nodes.griptape.ai")
|
|
1611
|
+
message = Panel(
|
|
1612
|
+
Align.center(
|
|
1613
|
+
f"[bold green]Engine is ready to receive events[/bold green]\n"
|
|
1614
|
+
f"[bold blue]Return to: [link={nodes_app_url}]{nodes_app_url}[/link] to access the Workflow Editor[/bold blue]",
|
|
1615
|
+
vertical="middle",
|
|
1616
|
+
),
|
|
1617
|
+
title="🚀 Griptape Nodes Engine Started",
|
|
1618
|
+
subtitle=f"[green]{engine_version}{session_info}[/green]",
|
|
1619
|
+
border_style="green",
|
|
1620
|
+
padding=(1, 4),
|
|
1621
|
+
)
|
|
1622
|
+
console.print(message)
|
|
1623
|
+
|
|
1624
|
+
def _load_libraries_from_provenance_system(self) -> None:
|
|
1625
|
+
"""Load libraries using the new provenance-based system with FSM.
|
|
1626
|
+
|
|
1627
|
+
This method converts libraries_to_register entries into LibraryProvenanceLocalFile
|
|
1628
|
+
objects and processes them through the LibraryDirectory and LibraryLifecycleFSM systems.
|
|
1629
|
+
"""
|
|
1630
|
+
# Get config manager
|
|
1631
|
+
config_mgr = GriptapeNodes.ConfigManager()
|
|
1632
|
+
|
|
1633
|
+
# Get the current libraries_to_register list
|
|
1634
|
+
user_libraries_section = "app_events.on_app_initialization_complete.libraries_to_register"
|
|
1635
|
+
libraries_to_register: list[str] = config_mgr.get_config_value(user_libraries_section)
|
|
1636
|
+
|
|
1637
|
+
if not libraries_to_register:
|
|
1638
|
+
logger.info("No libraries to register from config")
|
|
1639
|
+
return
|
|
1640
|
+
|
|
1641
|
+
# Convert string paths to LibraryProvenanceLocalFile objects
|
|
1642
|
+
for library_path in libraries_to_register:
|
|
1643
|
+
# Skip non-JSON files for now (requirement specifiers will need different handling)
|
|
1644
|
+
if not library_path.endswith(".json"):
|
|
1645
|
+
logger.debug("Skipping non-JSON library path: %s", library_path)
|
|
1646
|
+
continue
|
|
1647
|
+
|
|
1648
|
+
# Create provenance object
|
|
1649
|
+
provenance = LibraryProvenanceLocalFile(file_path=library_path)
|
|
1650
|
+
|
|
1651
|
+
# Add to directory as user candidate (defaults to active=True)
|
|
1652
|
+
# This automatically creates FSM and runs evaluation
|
|
1653
|
+
self._library_directory.add_user_candidate(provenance)
|
|
1654
|
+
|
|
1655
|
+
logger.debug("Added library provenance: %s", provenance.get_display_name())
|
|
1656
|
+
|
|
1657
|
+
# Get all candidates for evaluation
|
|
1658
|
+
all_candidates = self._library_directory.get_all_candidates()
|
|
1659
|
+
|
|
1660
|
+
logger.info("Evaluated %d library candidates through FSM lifecycle", len(all_candidates))
|
|
1661
|
+
|
|
1662
|
+
# Report on conflicts found
|
|
1663
|
+
self._report_library_name_conflicts()
|
|
1664
|
+
|
|
1665
|
+
# Get candidates that are ready for installation
|
|
1666
|
+
installable_candidates = self._library_directory.get_installable_candidates()
|
|
1667
|
+
|
|
1668
|
+
# Log any skipped libraries
|
|
1669
|
+
active_candidates = self._library_directory.get_active_candidates()
|
|
1670
|
+
for candidate in active_candidates:
|
|
1671
|
+
if candidate not in installable_candidates:
|
|
1672
|
+
blockers = self._library_directory.get_installation_blockers(candidate.provenance)
|
|
1673
|
+
if blockers:
|
|
1674
|
+
blocker_messages = [blocker.message for blocker in blockers]
|
|
1675
|
+
combined_message = "; ".join(blocker_messages)
|
|
1676
|
+
logger.info("Skipping library '%s' - %s", candidate.provenance.get_display_name(), combined_message)
|
|
1677
|
+
|
|
1678
|
+
logger.info("Installing and loading %d installable library candidates", len(installable_candidates))
|
|
1679
|
+
|
|
1680
|
+
# Process installable candidates through installation and loading
|
|
1681
|
+
for candidate in installable_candidates:
|
|
1682
|
+
if self._library_directory.install_library(candidate.provenance):
|
|
1683
|
+
self._library_directory.load_library(candidate.provenance)
|
|
1684
|
+
|
|
1685
|
+
def _report_library_name_conflicts(self) -> None:
|
|
1686
|
+
"""Report on library name conflicts found during evaluation."""
|
|
1687
|
+
conflicting_names = self._library_directory.get_all_conflicting_library_names()
|
|
1688
|
+
for library_name in conflicting_names:
|
|
1689
|
+
conflicting_provenances = self._library_directory.get_conflicting_provenances(library_name)
|
|
1690
|
+
logger.warning(
|
|
1691
|
+
"Library name conflict detected for '%s' across %d libraries: %s",
|
|
1692
|
+
library_name,
|
|
1693
|
+
len(conflicting_provenances),
|
|
1694
|
+
[p.get_display_name() for p in conflicting_provenances],
|
|
1695
|
+
)
|
|
1696
|
+
|
|
1592
1697
|
def _load_advanced_library_module(
|
|
1593
1698
|
self,
|
|
1594
1699
|
library_data: LibrarySchema,
|
|
@@ -1671,7 +1776,7 @@ class LibraryManager:
|
|
|
1671
1776
|
has_disqualifying_issues = False
|
|
1672
1777
|
for issue in version_issues:
|
|
1673
1778
|
problems.append(issue.message)
|
|
1674
|
-
if issue.severity ==
|
|
1779
|
+
if issue.severity == LibraryStatus.UNUSABLE:
|
|
1675
1780
|
has_disqualifying_issues = True
|
|
1676
1781
|
|
|
1677
1782
|
# Early exit if any version issues are disqualifying
|
|
@@ -1680,7 +1785,7 @@ class LibraryManager:
|
|
|
1680
1785
|
library_path=library_file_path,
|
|
1681
1786
|
library_name=library_data.name,
|
|
1682
1787
|
library_version=library_version,
|
|
1683
|
-
status=
|
|
1788
|
+
status=LibraryStatus.UNUSABLE,
|
|
1684
1789
|
problems=problems,
|
|
1685
1790
|
)
|
|
1686
1791
|
|
|
@@ -1747,13 +1852,13 @@ class LibraryManager:
|
|
|
1747
1852
|
|
|
1748
1853
|
# Create a LibraryInfo object based on load successes and problem count.
|
|
1749
1854
|
if not any_nodes_loaded_successfully:
|
|
1750
|
-
status =
|
|
1855
|
+
status = LibraryStatus.UNUSABLE
|
|
1751
1856
|
elif problems:
|
|
1752
1857
|
# Success, but errors.
|
|
1753
|
-
status =
|
|
1858
|
+
status = LibraryStatus.FLAWED
|
|
1754
1859
|
else:
|
|
1755
1860
|
# Flawless victory.
|
|
1756
|
-
status =
|
|
1861
|
+
status = LibraryStatus.GOOD
|
|
1757
1862
|
|
|
1758
1863
|
# Create a LibraryInfo object based on load successes and problem count.
|
|
1759
1864
|
return LibraryManager.LibraryInfo(
|
|
@@ -1845,7 +1950,7 @@ class LibraryManager:
|
|
|
1845
1950
|
library_path=sandbox_library_dir_as_posix,
|
|
1846
1951
|
library_name=library_data.name,
|
|
1847
1952
|
library_version=library_data.metadata.library_version,
|
|
1848
|
-
status=
|
|
1953
|
+
status=LibraryStatus.UNUSABLE,
|
|
1849
1954
|
problems=[
|
|
1850
1955
|
"Failed because a library with this name was already registered. Check the Settings to ensure duplicate libraries are not being loaded."
|
|
1851
1956
|
],
|
|
@@ -1900,7 +2005,7 @@ class LibraryManager:
|
|
|
1900
2005
|
|
|
1901
2006
|
paths_to_remove = set()
|
|
1902
2007
|
for library_path, library_info in self._library_file_path_to_info.items():
|
|
1903
|
-
if library_info.status ==
|
|
2008
|
+
if library_info.status == LibraryStatus.MISSING:
|
|
1904
2009
|
# Remove this file path from the config.
|
|
1905
2010
|
paths_to_remove.add(library_path.lower())
|
|
1906
2011
|
|
|
@@ -218,7 +218,7 @@ class NodeManager:
|
|
|
218
218
|
if parent_flow_name == old_name:
|
|
219
219
|
self._name_to_parent_flow_name[node_name] = new_name
|
|
220
220
|
|
|
221
|
-
def on_create_node_request(self, request: CreateNodeRequest) -> ResultPayload: # noqa: C901,
|
|
221
|
+
def on_create_node_request(self, request: CreateNodeRequest) -> ResultPayload: # noqa: C901, PLR0912, PLR0915
|
|
222
222
|
# Validate as much as possible before we actually create one.
|
|
223
223
|
parent_flow_name = request.override_parent_flow_name
|
|
224
224
|
parent_flow = None
|
|
@@ -320,6 +320,7 @@ class NodeManager:
|
|
|
320
320
|
|
|
321
321
|
logger.log(level=log_level, msg=details)
|
|
322
322
|
|
|
323
|
+
# Special handling for paired classes (e.g., create a Start node and it automatically creates a corresponding End node already connected).
|
|
323
324
|
if isinstance(node, StartLoopNode) and not request.initial_setup:
|
|
324
325
|
# If it's StartLoop, create an EndLoop and connect it to the StartLoop.
|
|
325
326
|
# Get the class name of the node
|
|
@@ -332,43 +333,42 @@ class NodeManager:
|
|
|
332
333
|
# Check and see if the class exists
|
|
333
334
|
libraries_with_node_type = LibraryRegistry.get_libraries_with_node_type(end_class_name)
|
|
334
335
|
if not libraries_with_node_type:
|
|
335
|
-
msg = f"
|
|
336
|
-
logger.error(msg)
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
)
|
|
348
|
-
)
|
|
349
|
-
if not isinstance(end_loop, CreateNodeResultSuccess):
|
|
350
|
-
msg = f"Failed to create EndLoop node for StartLoop node '{node.name}'"
|
|
351
|
-
logger.error(msg)
|
|
352
|
-
return CreateNodeResultFailure()
|
|
353
|
-
|
|
354
|
-
# Create Loop between output and input to the start node.
|
|
355
|
-
GriptapeNodes.handle_request(
|
|
356
|
-
CreateConnectionRequest(
|
|
357
|
-
source_node_name=node.name,
|
|
358
|
-
source_parameter_name="loop",
|
|
359
|
-
target_node_name=end_loop.node_name,
|
|
360
|
-
target_parameter_name="from_start",
|
|
336
|
+
msg = f"Attempted to create a paried set of nodes for Node '{final_node_name}'. Failed because paired class '{end_class_name}' does not exist for start class '{node_class_name}'. The corresponding node will have to be created by hand and attached manually."
|
|
337
|
+
logger.error(msg) # while this is bad, it's not unsalvageable, so we'll consider this a success.
|
|
338
|
+
else:
|
|
339
|
+
# Create the EndNode
|
|
340
|
+
end_loop = GriptapeNodes.handle_request(
|
|
341
|
+
CreateNodeRequest(
|
|
342
|
+
node_type=end_class_name,
|
|
343
|
+
metadata={
|
|
344
|
+
"position": {"x": node.metadata["position"]["x"] + 650, "y": node.metadata["position"]["y"]}
|
|
345
|
+
},
|
|
346
|
+
override_parent_flow_name=parent_flow_name,
|
|
347
|
+
)
|
|
361
348
|
)
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
349
|
+
if not isinstance(end_loop, CreateNodeResultSuccess):
|
|
350
|
+
msg = f"Attempted to create a paried set of nodes for Node '{final_node_name}'. Failed because paired class '{end_class_name}' failed to get created. The corresponding node will have to be created by hand and attached manually."
|
|
351
|
+
logger.error(msg) # while this is bad, it's not unsalvageable, so we'll consider this a success.
|
|
352
|
+
else:
|
|
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",
|
|
360
|
+
)
|
|
361
|
+
)
|
|
362
|
+
end_node = self.get_node_by_name(end_loop.node_name)
|
|
363
|
+
if not isinstance(end_node, EndLoopNode):
|
|
364
|
+
msg = f"Attempted to create a paried set of nodes for Node '{final_node_name}'. Failed because paired node '{end_loop.node_name}' was not a proper EndLoop instance. The corresponding node will have to be created by hand and attached manually."
|
|
365
|
+
logger.error(
|
|
366
|
+
msg
|
|
367
|
+
) # while this is bad, it's not unsalvageable, so we'll consider this a success.
|
|
368
|
+
else:
|
|
369
|
+
# create the connection - only when we've confirmed correct types
|
|
370
|
+
node.end_node = end_node
|
|
371
|
+
end_node.start_node = node
|
|
372
372
|
|
|
373
373
|
return CreateNodeResultSuccess(
|
|
374
374
|
node_name=node.name, node_type=node.__class__.__name__, specific_library_name=request.specific_library_name
|
|
@@ -428,7 +428,7 @@ class NodeManager:
|
|
|
428
428
|
parent_flow.clear_execution_queue()
|
|
429
429
|
return None
|
|
430
430
|
|
|
431
|
-
def on_delete_node_request(self, request: DeleteNodeRequest) -> ResultPayload: # noqa: C901, PLR0911 (complex logic, lots of edge cases)
|
|
431
|
+
def on_delete_node_request(self, request: DeleteNodeRequest) -> ResultPayload: # noqa: C901, PLR0911, PLR0912, PLR0915 (complex logic, lots of edge cases)
|
|
432
432
|
node_name = request.node_name
|
|
433
433
|
node = None
|
|
434
434
|
if node_name is None:
|
|
@@ -461,41 +461,55 @@ class NodeManager:
|
|
|
461
461
|
cancel_result = self.cancel_conditionally(parent_flow, parent_flow_name, node)
|
|
462
462
|
if cancel_result is not None:
|
|
463
463
|
return cancel_result
|
|
464
|
-
# Remove all connections from this Node
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
delete_request = DeleteConnectionRequest(
|
|
475
|
-
source_node_name=incoming_connection.source_node_name,
|
|
476
|
-
source_parameter_name=incoming_connection.source_parameter_name,
|
|
477
|
-
target_node_name=node_name,
|
|
478
|
-
target_parameter_name=incoming_connection.target_parameter_name,
|
|
479
|
-
)
|
|
480
|
-
delete_result = GriptapeNodes.handle_request(delete_request)
|
|
481
|
-
if isinstance(delete_result, ResultPayloadFailure):
|
|
482
|
-
details = f"Attempted to delete a Node '{node_name}'. Failed when attempting to delete Connection."
|
|
464
|
+
# Remove all connections from this Node using a loop to handle cascading deletions
|
|
465
|
+
any_connections_remain = True
|
|
466
|
+
while any_connections_remain:
|
|
467
|
+
# Assume we're done
|
|
468
|
+
any_connections_remain = False
|
|
469
|
+
|
|
470
|
+
list_node_connections_request = ListConnectionsForNodeRequest(node_name=node_name)
|
|
471
|
+
list_connections_result = GriptapeNodes.handle_request(request=list_node_connections_request)
|
|
472
|
+
if not isinstance(list_connections_result, ListConnectionsForNodeResultSuccess):
|
|
473
|
+
details = f"Attempted to delete a Node '{node_name}'. Failed because it could not gather Connections to the Node."
|
|
483
474
|
logger.error(details)
|
|
484
475
|
return DeleteNodeResultFailure()
|
|
485
476
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
477
|
+
# Check incoming connections
|
|
478
|
+
if list_connections_result.incoming_connections:
|
|
479
|
+
any_connections_remain = True
|
|
480
|
+
connection = list_connections_result.incoming_connections[0]
|
|
481
|
+
delete_request = DeleteConnectionRequest(
|
|
482
|
+
source_node_name=connection.source_node_name,
|
|
483
|
+
source_parameter_name=connection.source_parameter_name,
|
|
484
|
+
target_node_name=node_name,
|
|
485
|
+
target_parameter_name=connection.target_parameter_name,
|
|
486
|
+
)
|
|
487
|
+
delete_result = GriptapeNodes.handle_request(delete_request)
|
|
488
|
+
if isinstance(delete_result, ResultPayloadFailure):
|
|
489
|
+
details = (
|
|
490
|
+
f"Attempted to delete a Node '{node_name}'. Failed when attempting to delete Connection."
|
|
491
|
+
)
|
|
492
|
+
logger.error(details)
|
|
493
|
+
return DeleteNodeResultFailure()
|
|
494
|
+
continue # Refresh connection list after cascading deletions
|
|
495
|
+
|
|
496
|
+
# Check outgoing connections
|
|
497
|
+
if list_connections_result.outgoing_connections:
|
|
498
|
+
any_connections_remain = True
|
|
499
|
+
connection = list_connections_result.outgoing_connections[0]
|
|
500
|
+
delete_request = DeleteConnectionRequest(
|
|
501
|
+
source_node_name=node_name,
|
|
502
|
+
source_parameter_name=connection.source_parameter_name,
|
|
503
|
+
target_node_name=connection.target_node_name,
|
|
504
|
+
target_parameter_name=connection.target_parameter_name,
|
|
505
|
+
)
|
|
506
|
+
delete_result = GriptapeNodes.handle_request(delete_request)
|
|
507
|
+
if isinstance(delete_result, ResultPayloadFailure):
|
|
508
|
+
details = (
|
|
509
|
+
f"Attempted to delete a Node '{node_name}'. Failed when attempting to delete Connection."
|
|
510
|
+
)
|
|
511
|
+
logger.error(details)
|
|
512
|
+
return DeleteNodeResultFailure()
|
|
499
513
|
|
|
500
514
|
# Remove from the owning Flow
|
|
501
515
|
parent_flow.remove_node(node.name)
|
|
@@ -2355,7 +2369,7 @@ class NodeManager:
|
|
|
2355
2369
|
node_name=node.name,
|
|
2356
2370
|
)
|
|
2357
2371
|
if internal_command is None:
|
|
2358
|
-
details = f"Attempted to serialize set value for parameter'{parameter.name}' on node '{node.name}'. The set value will not be restored in anything that attempts to deserialize or save this node. The value for this parameter was not serialized because it did not match Griptape Nodes' criteria for serializability. To remedy, either update the value's type to support
|
|
2372
|
+
details = f"Attempted to serialize set value for parameter '{parameter.name}' on node '{node.name}'. The set value will not be restored in anything that attempts to deserialize or save this node. The value for this parameter was not serialized because it did not match Griptape Nodes' criteria for serializability. To remedy, either update the value's type to support serializability or mark the parameter as not serializable."
|
|
2359
2373
|
logger.warning(details)
|
|
2360
2374
|
else:
|
|
2361
2375
|
commands.append(internal_command)
|
|
@@ -2369,7 +2383,7 @@ class NodeManager:
|
|
|
2369
2383
|
node_name=node.name,
|
|
2370
2384
|
)
|
|
2371
2385
|
if output_command is None:
|
|
2372
|
-
details = f"Attempted to serialize output value for parameter '{parameter.name}' on node '{node.name}'. The output value will not be restored in anything that attempts to deserialize or save this node. The value for this parameter was not serialized because it did not match Griptape Nodes' criteria for serializability. To remedy, either update the value's type to support
|
|
2386
|
+
details = f"Attempted to serialize output value for parameter '{parameter.name}' on node '{node.name}'. The output value will not be restored in anything that attempts to deserialize or save this node. The value for this parameter was not serialized because it did not match Griptape Nodes' criteria for serializability. To remedy, either update the value's type to support serializability or mark the parameter as not serializable."
|
|
2373
2387
|
logger.warning(details)
|
|
2374
2388
|
else:
|
|
2375
2389
|
commands.append(output_command)
|
|
File without changes
|
|
File without changes
|