griptape-nodes 0.41.0__py3-none-any.whl → 0.43.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 +0 -0
- griptape_nodes/app/.python-version +0 -0
- griptape_nodes/app/__init__.py +1 -10
- griptape_nodes/app/api.py +199 -0
- griptape_nodes/app/app.py +140 -222
- griptape_nodes/app/watch.py +4 -2
- 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 +5 -3
- 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 +68 -368
- 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 +52 -20
- griptape_nodes/machines/fsm.py +16 -2
- griptape_nodes/machines/node_resolution.py +16 -14
- 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 +2 -2
- 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 +70 -8
- griptape_nodes/retained_mode/events/app_events.py +137 -12
- griptape_nodes/retained_mode/events/arbitrary_python_events.py +23 -0
- griptape_nodes/retained_mode/events/base_events.py +13 -31
- griptape_nodes/retained_mode/events/config_events.py +87 -11
- griptape_nodes/retained_mode/events/connection_events.py +56 -5
- griptape_nodes/retained_mode/events/context_events.py +27 -4
- griptape_nodes/retained_mode/events/execution_events.py +99 -14
- griptape_nodes/retained_mode/events/flow_events.py +165 -7
- griptape_nodes/retained_mode/events/generate_request_payload_schemas.py +0 -0
- griptape_nodes/retained_mode/events/library_events.py +195 -17
- griptape_nodes/retained_mode/events/logger_events.py +11 -0
- griptape_nodes/retained_mode/events/node_events.py +242 -22
- griptape_nodes/retained_mode/events/object_events.py +40 -4
- griptape_nodes/retained_mode/events/os_events.py +116 -3
- griptape_nodes/retained_mode/events/parameter_events.py +212 -8
- griptape_nodes/retained_mode/events/payload_registry.py +0 -0
- griptape_nodes/retained_mode/events/secrets_events.py +59 -7
- griptape_nodes/retained_mode/events/static_file_events.py +57 -4
- griptape_nodes/retained_mode/events/validation_events.py +39 -4
- griptape_nodes/retained_mode/events/workflow_events.py +188 -17
- griptape_nodes/retained_mode/griptape_nodes.py +89 -363
- griptape_nodes/retained_mode/managers/__init__.py +0 -0
- griptape_nodes/retained_mode/managers/agent_manager.py +49 -23
- 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 +146 -0
- griptape_nodes/retained_mode/managers/event_manager.py +14 -2
- griptape_nodes/retained_mode/managers/flow_manager.py +751 -64
- 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 +255 -40
- griptape_nodes/retained_mode/managers/node_manager.py +120 -103
- griptape_nodes/retained_mode/managers/object_manager.py +11 -3
- griptape_nodes/retained_mode/managers/operation_manager.py +0 -0
- griptape_nodes/retained_mode/managers/os_manager.py +582 -8
- griptape_nodes/retained_mode/managers/secrets_manager.py +4 -0
- griptape_nodes/retained_mode/managers/session_manager.py +328 -0
- griptape_nodes/retained_mode/managers/settings.py +7 -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 +722 -456
- griptape_nodes/retained_mode/retained_mode.py +44 -0
- griptape_nodes/retained_mode/utils/__init__.py +0 -0
- griptape_nodes/retained_mode/utils/engine_identity.py +141 -27
- 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.0.dist-info/METADATA +90 -0
- griptape_nodes-0.43.0.dist-info/RECORD +129 -0
- griptape_nodes-0.43.0.dist-info/WHEEL +4 -0
- {griptape_nodes-0.41.0.dist-info → griptape_nodes-0.43.0.dist-info}/entry_points.txt +1 -0
- griptape_nodes/app/app_sessions.py +0 -458
- griptape_nodes/retained_mode/utils/session_persistence.py +0 -105
- griptape_nodes-0.41.0.dist-info/METADATA +0 -78
- griptape_nodes-0.41.0.dist-info/RECORD +0 -112
- griptape_nodes-0.41.0.dist-info/WHEEL +0 -4
- griptape_nodes-0.41.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
|
|
@@ -58,6 +58,9 @@ from griptape_nodes.retained_mode.events.library_events import (
|
|
|
58
58
|
GetNodeMetadataFromLibraryRequest,
|
|
59
59
|
GetNodeMetadataFromLibraryResultFailure,
|
|
60
60
|
GetNodeMetadataFromLibraryResultSuccess,
|
|
61
|
+
ListCapableLibraryEventHandlersRequest,
|
|
62
|
+
ListCapableLibraryEventHandlersResultFailure,
|
|
63
|
+
ListCapableLibraryEventHandlersResultSuccess,
|
|
61
64
|
ListCategoriesInLibraryRequest,
|
|
62
65
|
ListCategoriesInLibraryResultFailure,
|
|
63
66
|
ListCategoriesInLibraryResultSuccess,
|
|
@@ -85,29 +88,44 @@ from griptape_nodes.retained_mode.events.library_events import (
|
|
|
85
88
|
UnloadLibraryFromRegistryResultSuccess,
|
|
86
89
|
)
|
|
87
90
|
from griptape_nodes.retained_mode.events.object_events import ClearAllObjectStateRequest
|
|
91
|
+
from griptape_nodes.retained_mode.events.payload_registry import PayloadRegistry
|
|
88
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
|
|
89
98
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
90
99
|
|
|
91
100
|
if TYPE_CHECKING:
|
|
101
|
+
from collections.abc import Callable
|
|
92
102
|
from types import ModuleType
|
|
93
103
|
|
|
94
104
|
from griptape_nodes.node_library.advanced_node_library import AdvancedNodeLibrary
|
|
95
|
-
from griptape_nodes.retained_mode.events.base_events import ResultPayload
|
|
105
|
+
from griptape_nodes.retained_mode.events.base_events import Payload, RequestPayload, ResultPayload
|
|
96
106
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
97
107
|
|
|
98
108
|
logger = logging.getLogger("griptape_nodes")
|
|
109
|
+
console = Console()
|
|
99
110
|
|
|
100
111
|
|
|
101
|
-
|
|
102
|
-
|
|
112
|
+
def _find_griptape_uv_bin() -> str:
|
|
113
|
+
"""Find the uv binary, checking dedicated Griptape installation first, then system uv.
|
|
103
114
|
|
|
104
|
-
|
|
105
|
-
|
|
115
|
+
Returns:
|
|
116
|
+
Path to the uv binary to use
|
|
117
|
+
"""
|
|
118
|
+
# Check for dedicated Griptape uv installation first
|
|
119
|
+
dedicated_uv_path = xdg_data_home() / "griptape_nodes" / "bin" / "uv"
|
|
120
|
+
if dedicated_uv_path.exists():
|
|
121
|
+
return str(dedicated_uv_path)
|
|
106
122
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
123
|
+
# Fall back to system uv installation
|
|
124
|
+
return uv.find_uv_bin()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class LibraryManager:
|
|
128
|
+
SANDBOX_LIBRARY_NAME = "Sandbox Library"
|
|
111
129
|
|
|
112
130
|
@dataclass
|
|
113
131
|
class LibraryInfo:
|
|
@@ -116,7 +134,7 @@ class LibraryManager:
|
|
|
116
134
|
Includes the status of the library, the file path, and any problems encountered during loading.
|
|
117
135
|
"""
|
|
118
136
|
|
|
119
|
-
status:
|
|
137
|
+
status: LibraryStatus
|
|
120
138
|
library_path: str
|
|
121
139
|
library_name: str | None = None
|
|
122
140
|
library_version: str | None = None
|
|
@@ -124,6 +142,13 @@ class LibraryManager:
|
|
|
124
142
|
|
|
125
143
|
_library_file_path_to_info: dict[str, LibraryInfo]
|
|
126
144
|
|
|
145
|
+
@dataclass
|
|
146
|
+
class RegisteredEventHandler:
|
|
147
|
+
"""Information regarding an event handler from a registered library."""
|
|
148
|
+
|
|
149
|
+
handler: Callable[[RequestPayload], ResultPayload]
|
|
150
|
+
library_data: LibrarySchema
|
|
151
|
+
|
|
127
152
|
# Stable module namespace mappings for workflow serialization
|
|
128
153
|
# These mappings ensure that dynamically loaded modules can be reliably imported
|
|
129
154
|
# in generated workflow code by providing stable, predictable import paths.
|
|
@@ -148,10 +173,16 @@ class LibraryManager:
|
|
|
148
173
|
self._dynamic_to_stable_module_mapping = {}
|
|
149
174
|
self._stable_to_dynamic_module_mapping = {}
|
|
150
175
|
self._library_to_stable_modules = {}
|
|
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()
|
|
151
179
|
|
|
152
180
|
event_manager.assign_manager_to_request_type(
|
|
153
181
|
ListRegisteredLibrariesRequest, self.on_list_registered_libraries_request
|
|
154
182
|
)
|
|
183
|
+
event_manager.assign_manager_to_request_type(
|
|
184
|
+
ListCapableLibraryEventHandlersRequest, self.on_list_capable_event_handlers
|
|
185
|
+
)
|
|
155
186
|
event_manager.assign_manager_to_request_type(
|
|
156
187
|
ListNodeTypesInLibraryRequest, self.on_list_node_types_in_library_request
|
|
157
188
|
)
|
|
@@ -223,10 +254,10 @@ class LibraryManager:
|
|
|
223
254
|
|
|
224
255
|
# Status emojis mapping
|
|
225
256
|
status_emoji = {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
257
|
+
LibraryStatus.GOOD: "✅",
|
|
258
|
+
LibraryStatus.FLAWED: "🟡",
|
|
259
|
+
LibraryStatus.UNUSABLE: "❌",
|
|
260
|
+
LibraryStatus.MISSING: "❓",
|
|
230
261
|
}
|
|
231
262
|
|
|
232
263
|
# Add rows for each library info
|
|
@@ -277,6 +308,33 @@ class LibraryManager:
|
|
|
277
308
|
return library_info
|
|
278
309
|
return None
|
|
279
310
|
|
|
311
|
+
def on_register_event_handler(
|
|
312
|
+
self,
|
|
313
|
+
request_type: type[RequestPayload],
|
|
314
|
+
handler: Callable[[RequestPayload], ResultPayload],
|
|
315
|
+
library_data: LibrarySchema,
|
|
316
|
+
) -> None:
|
|
317
|
+
"""Register an event handler for a specific request type from a library."""
|
|
318
|
+
if self._library_event_handler_mappings.get(request_type) is None:
|
|
319
|
+
self._library_event_handler_mappings[request_type] = {}
|
|
320
|
+
self._library_event_handler_mappings[request_type][library_data.name] = LibraryManager.RegisteredEventHandler(
|
|
321
|
+
handler=handler, library_data=library_data
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
def get_registered_event_handlers(self, request_type: type[Payload]) -> dict[str, RegisteredEventHandler]:
|
|
325
|
+
"""Get all registered event handlers for a specific request type."""
|
|
326
|
+
return self._library_event_handler_mappings.get(request_type, {})
|
|
327
|
+
|
|
328
|
+
def on_list_capable_event_handlers(self, request: ListCapableLibraryEventHandlersRequest) -> ResultPayload:
|
|
329
|
+
"""Get all registered event handlers for a specific request type."""
|
|
330
|
+
request_type = PayloadRegistry.get_type(request.request_type)
|
|
331
|
+
if request_type is None:
|
|
332
|
+
return ListCapableLibraryEventHandlersResultFailure(
|
|
333
|
+
exception=KeyError(f"Request type '{request.request_type}' is not registered in the PayloadRegistry.")
|
|
334
|
+
)
|
|
335
|
+
handler_mappings = self.get_registered_event_handlers(request_type)
|
|
336
|
+
return ListCapableLibraryEventHandlersResultSuccess(handlers=list(handler_mappings.keys()))
|
|
337
|
+
|
|
280
338
|
def on_list_registered_libraries_request(self, _request: ListRegisteredLibrariesRequest) -> ResultPayload:
|
|
281
339
|
# Make a COPY of the list
|
|
282
340
|
snapshot_list = LibraryRegistry.list_libraries()
|
|
@@ -350,7 +408,7 @@ class LibraryManager:
|
|
|
350
408
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
351
409
|
library_path=file_path,
|
|
352
410
|
library_name=None,
|
|
353
|
-
status=
|
|
411
|
+
status=LibraryStatus.MISSING,
|
|
354
412
|
problems=[
|
|
355
413
|
"Library could not be found at the file path specified. It will be removed from the configuration."
|
|
356
414
|
],
|
|
@@ -366,7 +424,7 @@ class LibraryManager:
|
|
|
366
424
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
367
425
|
library_path=file_path,
|
|
368
426
|
library_name=None,
|
|
369
|
-
status=
|
|
427
|
+
status=LibraryStatus.UNUSABLE,
|
|
370
428
|
problems=["Library file not formatted as proper JSON."],
|
|
371
429
|
)
|
|
372
430
|
except Exception as err:
|
|
@@ -375,7 +433,7 @@ class LibraryManager:
|
|
|
375
433
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
376
434
|
library_path=file_path,
|
|
377
435
|
library_name=None,
|
|
378
|
-
status=
|
|
436
|
+
status=LibraryStatus.UNUSABLE,
|
|
379
437
|
problems=[f"Exception occurred when attempting to load the library: {err}."],
|
|
380
438
|
)
|
|
381
439
|
|
|
@@ -399,7 +457,7 @@ class LibraryManager:
|
|
|
399
457
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
400
458
|
library_path=file_path,
|
|
401
459
|
library_name=library_name,
|
|
402
|
-
status=
|
|
460
|
+
status=LibraryStatus.UNUSABLE,
|
|
403
461
|
problems=problems,
|
|
404
462
|
)
|
|
405
463
|
except Exception as err:
|
|
@@ -408,7 +466,7 @@ class LibraryManager:
|
|
|
408
466
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
409
467
|
library_path=file_path,
|
|
410
468
|
library_name=library_name,
|
|
411
|
-
status=
|
|
469
|
+
status=LibraryStatus.UNUSABLE,
|
|
412
470
|
problems=[f"Library file did not match the library schema specified due to: {err}"],
|
|
413
471
|
)
|
|
414
472
|
|
|
@@ -482,7 +540,7 @@ class LibraryManager:
|
|
|
482
540
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
483
541
|
library_path=sandbox_library_dir_as_posix,
|
|
484
542
|
library_name=LibraryManager.SANDBOX_LIBRARY_NAME,
|
|
485
|
-
status=
|
|
543
|
+
status=LibraryStatus.MISSING,
|
|
486
544
|
problems=["Sandbox directory does not exist."],
|
|
487
545
|
)
|
|
488
546
|
|
|
@@ -537,7 +595,7 @@ class LibraryManager:
|
|
|
537
595
|
return LoadLibraryMetadataFromFileResultFailure(
|
|
538
596
|
library_path=sandbox_library_dir_as_posix,
|
|
539
597
|
library_name=LibraryManager.SANDBOX_LIBRARY_NAME,
|
|
540
|
-
status=
|
|
598
|
+
status=LibraryStatus.UNUSABLE,
|
|
541
599
|
problems=["Could not get engine version for sandbox library generation."],
|
|
542
600
|
)
|
|
543
601
|
|
|
@@ -621,7 +679,7 @@ class LibraryManager:
|
|
|
621
679
|
self._library_file_path_to_info[file_path] = LibraryManager.LibraryInfo(
|
|
622
680
|
library_path=file_path,
|
|
623
681
|
library_name=None,
|
|
624
|
-
status=
|
|
682
|
+
status=LibraryStatus.MISSING,
|
|
625
683
|
problems=[
|
|
626
684
|
"Library could not be found at the file path specified. It will be removed from the configuration."
|
|
627
685
|
],
|
|
@@ -655,7 +713,7 @@ class LibraryManager:
|
|
|
655
713
|
self._library_file_path_to_info[file_path] = LibraryManager.LibraryInfo(
|
|
656
714
|
library_path=file_path,
|
|
657
715
|
library_name=library_data.name,
|
|
658
|
-
status=
|
|
716
|
+
status=LibraryStatus.UNUSABLE,
|
|
659
717
|
problems=[
|
|
660
718
|
f"Library's version string '{library_data.metadata.library_version}' wasn't valid. Must be in major.minor.patch format."
|
|
661
719
|
],
|
|
@@ -682,7 +740,7 @@ class LibraryManager:
|
|
|
682
740
|
library_path=file_path,
|
|
683
741
|
library_name=library_data.name,
|
|
684
742
|
library_version=library_version,
|
|
685
|
-
status=
|
|
743
|
+
status=LibraryStatus.UNUSABLE,
|
|
686
744
|
problems=[
|
|
687
745
|
f"Failed to load Advanced Library module from '{library_data.advanced_library_path}': {err}"
|
|
688
746
|
],
|
|
@@ -706,7 +764,7 @@ class LibraryManager:
|
|
|
706
764
|
library_path=file_path,
|
|
707
765
|
library_name=library_data.name,
|
|
708
766
|
library_version=library_version,
|
|
709
|
-
status=
|
|
767
|
+
status=LibraryStatus.UNUSABLE,
|
|
710
768
|
problems=[
|
|
711
769
|
"Failed because a library with this name was already registered. Check the Settings to ensure duplicate libraries are not being loaded."
|
|
712
770
|
],
|
|
@@ -735,13 +793,35 @@ class LibraryManager:
|
|
|
735
793
|
library_path=file_path,
|
|
736
794
|
library_name=library_data.name,
|
|
737
795
|
library_version=library_version,
|
|
738
|
-
status=
|
|
796
|
+
status=LibraryStatus.UNUSABLE,
|
|
739
797
|
problems=[str(e)],
|
|
740
798
|
)
|
|
741
799
|
details = f"Attempted to load Library JSON file from '{json_path}'. Failed when creating the virtual environment: {e}."
|
|
742
800
|
logger.error(details)
|
|
743
801
|
return RegisterLibraryFromFileResultFailure()
|
|
744
802
|
if self._can_write_to_venv_location(library_venv_python_path):
|
|
803
|
+
# Check disk space before installing dependencies
|
|
804
|
+
config_manager = GriptapeNodes.ConfigManager()
|
|
805
|
+
min_space_gb = config_manager.get_config_value("minimum_disk_space_gb_libraries")
|
|
806
|
+
if not OSManager.check_available_disk_space(Path(venv_path), min_space_gb):
|
|
807
|
+
error_msg = OSManager.format_disk_space_error(Path(venv_path))
|
|
808
|
+
logger.error(
|
|
809
|
+
"Attempted to load Library JSON from '%s'. Failed when installing dependencies (requires %.1f GB): %s",
|
|
810
|
+
json_path,
|
|
811
|
+
min_space_gb,
|
|
812
|
+
error_msg,
|
|
813
|
+
)
|
|
814
|
+
self._library_file_path_to_info[file_path] = LibraryManager.LibraryInfo(
|
|
815
|
+
library_path=file_path,
|
|
816
|
+
library_name=library_data.name,
|
|
817
|
+
library_version=library_version,
|
|
818
|
+
status=LibraryStatus.UNUSABLE,
|
|
819
|
+
problems=[
|
|
820
|
+
f"Insufficient disk space for dependencies (requires {min_space_gb} GB): {error_msg}"
|
|
821
|
+
],
|
|
822
|
+
)
|
|
823
|
+
return RegisterLibraryFromFileResultFailure()
|
|
824
|
+
|
|
745
825
|
# Grab the python executable from the virtual environment so that we can pip install there
|
|
746
826
|
logger.info(
|
|
747
827
|
"Installing dependencies for library '%s' with pip in venv at %s", library_data.name, venv_path
|
|
@@ -771,11 +851,12 @@ class LibraryManager:
|
|
|
771
851
|
except subprocess.CalledProcessError as e:
|
|
772
852
|
# Failed to create the library
|
|
773
853
|
error_details = f"return code={e.returncode}, stdout={e.stdout}, stderr={e.stderr}"
|
|
854
|
+
|
|
774
855
|
self._library_file_path_to_info[file_path] = LibraryManager.LibraryInfo(
|
|
775
856
|
library_path=file_path,
|
|
776
857
|
library_name=library_data.name,
|
|
777
858
|
library_version=library_version,
|
|
778
|
-
status=
|
|
859
|
+
status=LibraryStatus.UNUSABLE,
|
|
779
860
|
problems=[f"Dependency installation failed: {error_details}"],
|
|
780
861
|
)
|
|
781
862
|
details = f"Attempted to load Library JSON file from '{json_path}'. Failed when installing dependencies: {error_details}"
|
|
@@ -807,7 +888,9 @@ class LibraryManager:
|
|
|
807
888
|
else:
|
|
808
889
|
# We had an existing category. Union our changes into it (not replacing anything that matched).
|
|
809
890
|
existing_category_contents = get_category_result.contents
|
|
810
|
-
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
|
+
}
|
|
811
894
|
set_category_request = SetConfigCategoryRequest(
|
|
812
895
|
category=library_data_setting.category, contents=existing_category_contents
|
|
813
896
|
)
|
|
@@ -830,15 +913,15 @@ class LibraryManager:
|
|
|
830
913
|
self._library_file_path_to_info[file_path] = library_load_results
|
|
831
914
|
|
|
832
915
|
match library_load_results.status:
|
|
833
|
-
case
|
|
916
|
+
case LibraryStatus.GOOD:
|
|
834
917
|
details = f"Successfully loaded Library '{library_data.name}' from JSON file at {json_path}"
|
|
835
918
|
logger.info(details)
|
|
836
919
|
return RegisterLibraryFromFileResultSuccess(library_name=library_data.name)
|
|
837
|
-
case
|
|
920
|
+
case LibraryStatus.FLAWED:
|
|
838
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."
|
|
839
922
|
logger.warning(details)
|
|
840
923
|
return RegisterLibraryFromFileResultSuccess(library_name=library_data.name)
|
|
841
|
-
case
|
|
924
|
+
case LibraryStatus.UNUSABLE:
|
|
842
925
|
details = f"Attempted to load Library JSON file from '{json_path}'. Failed because no nodes were loaded. Check the log for more details."
|
|
843
926
|
logger.error(details)
|
|
844
927
|
return RegisterLibraryFromFileResultFailure()
|
|
@@ -863,10 +946,23 @@ class LibraryManager:
|
|
|
863
946
|
logger.error(details)
|
|
864
947
|
return RegisterLibraryFromRequirementSpecifierResultFailure()
|
|
865
948
|
if self._can_write_to_venv_location(library_python_venv_path):
|
|
949
|
+
# Check disk space before installing dependencies
|
|
950
|
+
config_manager = GriptapeNodes.ConfigManager()
|
|
951
|
+
min_space_gb = config_manager.get_config_value("minimum_disk_space_gb_libraries")
|
|
952
|
+
if not OSManager.check_available_disk_space(Path(venv_path), min_space_gb):
|
|
953
|
+
error_msg = OSManager.format_disk_space_error(Path(venv_path))
|
|
954
|
+
logger.error(
|
|
955
|
+
"Attempted to install library '%s'. Failed when installing dependencies (requires %.1f GB): %s",
|
|
956
|
+
request.requirement_specifier,
|
|
957
|
+
min_space_gb,
|
|
958
|
+
error_msg,
|
|
959
|
+
)
|
|
960
|
+
return RegisterLibraryFromRequirementSpecifierResultFailure()
|
|
961
|
+
|
|
866
962
|
logger.info("Installing dependency '%s' with pip in venv at %s", package_name, venv_path)
|
|
867
963
|
subprocess.run( # noqa: S603
|
|
868
964
|
[
|
|
869
|
-
|
|
965
|
+
_find_griptape_uv_bin(),
|
|
870
966
|
"pip",
|
|
871
967
|
"install",
|
|
872
968
|
request.requirement_specifier,
|
|
@@ -922,6 +1018,19 @@ class LibraryManager:
|
|
|
922
1018
|
if library_venv_path.exists():
|
|
923
1019
|
logger.debug("Virtual environment already exists at %s", library_venv_path)
|
|
924
1020
|
else:
|
|
1021
|
+
# Check disk space before creating virtual environment
|
|
1022
|
+
config_manager = GriptapeNodes.ConfigManager()
|
|
1023
|
+
min_space_gb = config_manager.get_config_value("minimum_disk_space_gb_libraries")
|
|
1024
|
+
if not OSManager.check_available_disk_space(library_venv_path.parent, min_space_gb):
|
|
1025
|
+
error_msg = OSManager.format_disk_space_error(library_venv_path.parent)
|
|
1026
|
+
logger.error(
|
|
1027
|
+
"Attempted to create virtual environment (requires %.1f GB). Failed: %s", min_space_gb, error_msg
|
|
1028
|
+
)
|
|
1029
|
+
error_message = (
|
|
1030
|
+
f"Disk space error creating virtual environment (requires {min_space_gb} GB): {error_msg}"
|
|
1031
|
+
)
|
|
1032
|
+
raise RuntimeError(error_message)
|
|
1033
|
+
|
|
925
1034
|
try:
|
|
926
1035
|
logger.info("Creating virtual environment at %s with Python %s", library_venv_path, python_version)
|
|
927
1036
|
subprocess.run( # noqa: S603
|
|
@@ -1394,6 +1503,8 @@ class LibraryManager:
|
|
|
1394
1503
|
return node_class
|
|
1395
1504
|
|
|
1396
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
|
+
|
|
1397
1508
|
# Load metadata for all libraries to determine which ones can be safely loaded
|
|
1398
1509
|
metadata_request = LoadMetadataForAllLibrariesRequest()
|
|
1399
1510
|
metadata_result = self.load_metadata_for_all_libraries_request(metadata_request)
|
|
@@ -1441,6 +1552,9 @@ class LibraryManager:
|
|
|
1441
1552
|
self._remove_missing_libraries_from_config(config_category=user_libraries_section)
|
|
1442
1553
|
|
|
1443
1554
|
def on_app_initialization_complete(self, _payload: AppInitializationComplete) -> None:
|
|
1555
|
+
GriptapeNodes.EngineIdentityManager().initialize_engine_id()
|
|
1556
|
+
GriptapeNodes.SessionManager().get_saved_session_id()
|
|
1557
|
+
|
|
1444
1558
|
# App just got init'd. See if there are library JSONs to load!
|
|
1445
1559
|
self.load_all_libraries_from_config()
|
|
1446
1560
|
|
|
@@ -1479,6 +1593,107 @@ class LibraryManager:
|
|
|
1479
1593
|
# Go tell the Workflow Manager that it's turn is now.
|
|
1480
1594
|
GriptapeNodes.WorkflowManager().on_libraries_initialization_complete()
|
|
1481
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
|
+
|
|
1482
1697
|
def _load_advanced_library_module(
|
|
1483
1698
|
self,
|
|
1484
1699
|
library_data: LibrarySchema,
|
|
@@ -1561,7 +1776,7 @@ class LibraryManager:
|
|
|
1561
1776
|
has_disqualifying_issues = False
|
|
1562
1777
|
for issue in version_issues:
|
|
1563
1778
|
problems.append(issue.message)
|
|
1564
|
-
if issue.severity ==
|
|
1779
|
+
if issue.severity == LibraryStatus.UNUSABLE:
|
|
1565
1780
|
has_disqualifying_issues = True
|
|
1566
1781
|
|
|
1567
1782
|
# Early exit if any version issues are disqualifying
|
|
@@ -1570,7 +1785,7 @@ class LibraryManager:
|
|
|
1570
1785
|
library_path=library_file_path,
|
|
1571
1786
|
library_name=library_data.name,
|
|
1572
1787
|
library_version=library_version,
|
|
1573
|
-
status=
|
|
1788
|
+
status=LibraryStatus.UNUSABLE,
|
|
1574
1789
|
problems=problems,
|
|
1575
1790
|
)
|
|
1576
1791
|
|
|
@@ -1637,13 +1852,13 @@ class LibraryManager:
|
|
|
1637
1852
|
|
|
1638
1853
|
# Create a LibraryInfo object based on load successes and problem count.
|
|
1639
1854
|
if not any_nodes_loaded_successfully:
|
|
1640
|
-
status =
|
|
1855
|
+
status = LibraryStatus.UNUSABLE
|
|
1641
1856
|
elif problems:
|
|
1642
1857
|
# Success, but errors.
|
|
1643
|
-
status =
|
|
1858
|
+
status = LibraryStatus.FLAWED
|
|
1644
1859
|
else:
|
|
1645
1860
|
# Flawless victory.
|
|
1646
|
-
status =
|
|
1861
|
+
status = LibraryStatus.GOOD
|
|
1647
1862
|
|
|
1648
1863
|
# Create a LibraryInfo object based on load successes and problem count.
|
|
1649
1864
|
return LibraryManager.LibraryInfo(
|
|
@@ -1735,7 +1950,7 @@ class LibraryManager:
|
|
|
1735
1950
|
library_path=sandbox_library_dir_as_posix,
|
|
1736
1951
|
library_name=library_data.name,
|
|
1737
1952
|
library_version=library_data.metadata.library_version,
|
|
1738
|
-
status=
|
|
1953
|
+
status=LibraryStatus.UNUSABLE,
|
|
1739
1954
|
problems=[
|
|
1740
1955
|
"Failed because a library with this name was already registered. Check the Settings to ensure duplicate libraries are not being loaded."
|
|
1741
1956
|
],
|
|
@@ -1790,7 +2005,7 @@ class LibraryManager:
|
|
|
1790
2005
|
|
|
1791
2006
|
paths_to_remove = set()
|
|
1792
2007
|
for library_path, library_info in self._library_file_path_to_info.items():
|
|
1793
|
-
if library_info.status ==
|
|
2008
|
+
if library_info.status == LibraryStatus.MISSING:
|
|
1794
2009
|
# Remove this file path from the config.
|
|
1795
2010
|
paths_to_remove.add(library_path.lower())
|
|
1796
2011
|
|