griptape-nodes 0.62.2__py3-none-any.whl → 0.63.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/cli/commands/libraries.py +6 -21
- griptape_nodes/drivers/thread_storage/__init__.py +15 -0
- griptape_nodes/drivers/thread_storage/base_thread_storage_driver.py +106 -0
- griptape_nodes/drivers/thread_storage/griptape_cloud_thread_storage_driver.py +213 -0
- griptape_nodes/drivers/thread_storage/local_thread_storage_driver.py +137 -0
- griptape_nodes/drivers/thread_storage/thread_storage_backend.py +10 -0
- griptape_nodes/node_library/library_registry.py +16 -9
- griptape_nodes/node_library/workflow_registry.py +1 -1
- griptape_nodes/retained_mode/events/agent_events.py +232 -9
- griptape_nodes/retained_mode/events/app_events.py +38 -0
- griptape_nodes/retained_mode/events/library_events.py +32 -3
- griptape_nodes/retained_mode/events/os_events.py +101 -1
- griptape_nodes/retained_mode/managers/agent_manager.py +335 -135
- griptape_nodes/retained_mode/managers/fitness_problems/__init__.py +1 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/__init__.py +59 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/advanced_library_load_failure_problem.py +33 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/after_library_callback_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/before_library_callback_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/create_config_category_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/dependency_installation_failed_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/deprecated_node_warning_problem.py +83 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/duplicate_library_problem.py +28 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/duplicate_node_registration_problem.py +44 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/engine_version_error_problem.py +28 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/insufficient_disk_space_problem.py +33 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/invalid_version_string_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_json_decode_problem.py +28 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_load_exception_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_not_found_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_problem.py +20 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_schema_exception_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_schema_validation_problem.py +38 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/modified_parameters_set_deprecation_warning_problem.py +44 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/modified_parameters_set_removed_problem.py +44 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/node_class_not_base_node_problem.py +40 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/node_class_not_found_problem.py +38 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/node_module_import_problem.py +53 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/sandbox_directory_missing_problem.py +28 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/ui_options_field_modified_incompatible_problem.py +44 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/ui_options_field_modified_warning_problem.py +35 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/update_config_category_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/venv_creation_failed_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/__init__.py +75 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/deprecated_node_in_workflow_problem.py +83 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_dependency_version_string_problem.py +38 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_library_version_string_problem.py +38 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_metadata_schema_problem.py +31 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_metadata_section_count_problem.py +31 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_toml_format_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_not_registered_problem.py +35 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_below_required_problem.py +41 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_large_difference_problem.py +41 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_major_mismatch_problem.py +41 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_minor_difference_problem.py +41 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/missing_creation_date_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/missing_last_modified_date_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/missing_toml_section_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/node_type_not_found_problem.py +51 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/workflow_not_found_problem.py +27 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/workflow_problem.py +20 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/workflow_schema_version_problem.py +39 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +17 -3
- griptape_nodes/retained_mode/managers/library_manager.py +226 -77
- griptape_nodes/retained_mode/managers/os_manager.py +172 -1
- griptape_nodes/retained_mode/managers/settings.py +5 -0
- griptape_nodes/retained_mode/managers/version_compatibility_manager.py +76 -51
- griptape_nodes/retained_mode/managers/workflow_manager.py +237 -159
- griptape_nodes/servers/static.py +18 -19
- griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +16 -12
- griptape_nodes/version_compatibility/workflow_versions/v0_7_0/local_executor_argument_addition.py +6 -3
- {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/METADATA +2 -1
- {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/RECORD +74 -21
- {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/WHEEL +0 -0
- {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/entry_points.txt +0 -0
|
@@ -9,6 +9,7 @@ import platform
|
|
|
9
9
|
import subprocess
|
|
10
10
|
import sys
|
|
11
11
|
import sysconfig
|
|
12
|
+
from collections import defaultdict
|
|
12
13
|
from dataclasses import dataclass, field
|
|
13
14
|
from importlib.resources import files
|
|
14
15
|
from pathlib import Path
|
|
@@ -36,12 +37,15 @@ from griptape_nodes.node_library.library_registry import (
|
|
|
36
37
|
)
|
|
37
38
|
from griptape_nodes.retained_mode.events.app_events import (
|
|
38
39
|
AppInitializationComplete,
|
|
40
|
+
EngineInitializationProgress,
|
|
39
41
|
GetEngineVersionRequest,
|
|
40
42
|
GetEngineVersionResultSuccess,
|
|
43
|
+
InitializationPhase,
|
|
44
|
+
InitializationStatus,
|
|
41
45
|
)
|
|
42
46
|
|
|
43
47
|
# Runtime imports for ResultDetails since it's used at runtime
|
|
44
|
-
from griptape_nodes.retained_mode.events.base_events import ResultDetails
|
|
48
|
+
from griptape_nodes.retained_mode.events.base_events import AppEvent, ResultDetails
|
|
45
49
|
from griptape_nodes.retained_mode.events.config_events import (
|
|
46
50
|
GetConfigCategoryRequest,
|
|
47
51
|
GetConfigCategoryResultSuccess,
|
|
@@ -72,6 +76,9 @@ from griptape_nodes.retained_mode.events.library_events import (
|
|
|
72
76
|
ListNodeTypesInLibraryResultSuccess,
|
|
73
77
|
ListRegisteredLibrariesRequest,
|
|
74
78
|
ListRegisteredLibrariesResultSuccess,
|
|
79
|
+
LoadLibrariesRequest,
|
|
80
|
+
LoadLibrariesResultFailure,
|
|
81
|
+
LoadLibrariesResultSuccess,
|
|
75
82
|
LoadLibraryMetadataFromFileRequest,
|
|
76
83
|
LoadLibraryMetadataFromFileResultFailure,
|
|
77
84
|
LoadLibraryMetadataFromFileResultSuccess,
|
|
@@ -93,6 +100,29 @@ from griptape_nodes.retained_mode.events.library_events import (
|
|
|
93
100
|
from griptape_nodes.retained_mode.events.object_events import ClearAllObjectStateRequest
|
|
94
101
|
from griptape_nodes.retained_mode.events.payload_registry import PayloadRegistry
|
|
95
102
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
103
|
+
from griptape_nodes.retained_mode.managers.fitness_problems.libraries import (
|
|
104
|
+
AdvancedLibraryLoadFailureProblem,
|
|
105
|
+
AfterLibraryCallbackProblem,
|
|
106
|
+
BeforeLibraryCallbackProblem,
|
|
107
|
+
CreateConfigCategoryProblem,
|
|
108
|
+
DependencyInstallationFailedProblem,
|
|
109
|
+
DuplicateLibraryProblem,
|
|
110
|
+
EngineVersionErrorProblem,
|
|
111
|
+
InsufficientDiskSpaceProblem,
|
|
112
|
+
InvalidVersionStringProblem,
|
|
113
|
+
LibraryJsonDecodeProblem,
|
|
114
|
+
LibraryLoadExceptionProblem,
|
|
115
|
+
LibraryNotFoundProblem,
|
|
116
|
+
LibraryProblem,
|
|
117
|
+
LibrarySchemaExceptionProblem,
|
|
118
|
+
LibrarySchemaValidationProblem,
|
|
119
|
+
NodeClassNotBaseNodeProblem,
|
|
120
|
+
NodeClassNotFoundProblem,
|
|
121
|
+
NodeModuleImportProblem,
|
|
122
|
+
SandboxDirectoryMissingProblem,
|
|
123
|
+
UpdateConfigCategoryProblem,
|
|
124
|
+
VenvCreationFailedProblem,
|
|
125
|
+
)
|
|
96
126
|
from griptape_nodes.retained_mode.managers.library_lifecycle.library_directory import LibraryDirectory
|
|
97
127
|
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.local_file import (
|
|
98
128
|
LibraryProvenanceLocalFile,
|
|
@@ -131,7 +161,7 @@ class LibraryManager:
|
|
|
131
161
|
library_path: str
|
|
132
162
|
library_name: str | None = None
|
|
133
163
|
library_version: str | None = None
|
|
134
|
-
problems: list[
|
|
164
|
+
problems: list[LibraryProblem] = field(default_factory=list)
|
|
135
165
|
|
|
136
166
|
_library_file_path_to_info: dict[str, LibraryInfo]
|
|
137
167
|
|
|
@@ -213,7 +243,8 @@ class LibraryManager:
|
|
|
213
243
|
event_manager.assign_manager_to_request_type(
|
|
214
244
|
UnloadLibraryFromRegistryRequest, self.unload_library_from_registry_request
|
|
215
245
|
)
|
|
216
|
-
event_manager.assign_manager_to_request_type(ReloadAllLibrariesRequest, self.
|
|
246
|
+
event_manager.assign_manager_to_request_type(ReloadAllLibrariesRequest, self.reload_libraries_request)
|
|
247
|
+
event_manager.assign_manager_to_request_type(LoadLibrariesRequest, self.load_libraries_request)
|
|
217
248
|
|
|
218
249
|
event_manager.add_listener_to_app_event(
|
|
219
250
|
AppInitializationComplete,
|
|
@@ -237,14 +268,10 @@ class LibraryManager:
|
|
|
237
268
|
console.print(panel)
|
|
238
269
|
return
|
|
239
270
|
|
|
240
|
-
# Create a table with
|
|
241
|
-
# Using SQUARE box style which includes row dividers
|
|
271
|
+
# Create a table with two columns and row dividers
|
|
242
272
|
table = Table(show_header=True, box=HEAVY_EDGE, show_lines=True, expand=True)
|
|
243
|
-
table.add_column("Library
|
|
244
|
-
table.add_column("
|
|
245
|
-
table.add_column("Version", style="green")
|
|
246
|
-
table.add_column("File Path", style="cyan")
|
|
247
|
-
table.add_column("Problems", style="yellow")
|
|
273
|
+
table.add_column("Library", style="green", ratio=1)
|
|
274
|
+
table.add_column("Problems", style="yellow", ratio=1)
|
|
248
275
|
|
|
249
276
|
# Status emojis mapping
|
|
250
277
|
status_emoji = {
|
|
@@ -254,17 +281,20 @@ class LibraryManager:
|
|
|
254
281
|
LibraryStatus.MISSING: "[red]?[/red]",
|
|
255
282
|
}
|
|
256
283
|
|
|
284
|
+
# Status text mapping (colored)
|
|
285
|
+
status_text = {
|
|
286
|
+
LibraryStatus.GOOD: "[green](GOOD)[/green]",
|
|
287
|
+
LibraryStatus.FLAWED: "[yellow](FLAWED)[/yellow]",
|
|
288
|
+
LibraryStatus.UNUSABLE: "[red](UNUSABLE)[/red]",
|
|
289
|
+
LibraryStatus.MISSING: "[red](MISSING)[/red]",
|
|
290
|
+
}
|
|
291
|
+
|
|
257
292
|
# Add rows for each library info
|
|
258
293
|
for lib_info in library_infos:
|
|
259
|
-
#
|
|
260
|
-
file_path = lib_info.library_path
|
|
261
|
-
file_path_text = Text(file_path, style="cyan")
|
|
262
|
-
file_path_text.overflow = "fold" # Force wrapping
|
|
263
|
-
|
|
264
|
-
# Library name column with emoji based on status
|
|
294
|
+
# Library column with emoji, name, version, colored status, and file path underneath
|
|
265
295
|
emoji = status_emoji.get(lib_info.status, "ERROR: Unknown/Unexpected Library Status")
|
|
296
|
+
colored_status = status_text.get(lib_info.status, "(UNKNOWN)")
|
|
266
297
|
name = lib_info.library_name if lib_info.library_name else "*UNKNOWN*"
|
|
267
|
-
library_name = f"{emoji} - {name}"
|
|
268
298
|
|
|
269
299
|
library_version = lib_info.library_version
|
|
270
300
|
if library_version:
|
|
@@ -272,17 +302,36 @@ class LibraryManager:
|
|
|
272
302
|
else:
|
|
273
303
|
version_str = "*UNKNOWN*"
|
|
274
304
|
|
|
275
|
-
|
|
305
|
+
file_path = lib_info.library_path
|
|
306
|
+
library_name_with_details = Text.from_markup(
|
|
307
|
+
f"{emoji} - {name} v{version_str} {colored_status}\n[cyan dim]{file_path}[/cyan dim]"
|
|
308
|
+
)
|
|
309
|
+
library_name_with_details.overflow = "fold"
|
|
310
|
+
|
|
311
|
+
# Problems column - collate by type then format
|
|
276
312
|
if not lib_info.problems:
|
|
277
313
|
problems = "No problems detected."
|
|
278
|
-
elif len(lib_info.problems) == 1:
|
|
279
|
-
problems = lib_info.problems[0]
|
|
280
314
|
else:
|
|
281
|
-
#
|
|
282
|
-
|
|
315
|
+
# Group problems by type
|
|
316
|
+
problems_by_type = defaultdict(list)
|
|
317
|
+
for problem in lib_info.problems:
|
|
318
|
+
problems_by_type[type(problem)].append(problem)
|
|
319
|
+
|
|
320
|
+
# Collate each group
|
|
321
|
+
collated_strings = []
|
|
322
|
+
for problem_class, instances in problems_by_type.items():
|
|
323
|
+
collated_display = problem_class.collate_problems_for_display(instances)
|
|
324
|
+
collated_strings.append(collated_display)
|
|
325
|
+
|
|
326
|
+
# Format for display
|
|
327
|
+
if len(collated_strings) == 1:
|
|
328
|
+
problems = collated_strings[0]
|
|
329
|
+
else:
|
|
330
|
+
# Number the problems when there's more than one
|
|
331
|
+
problems = "\n".join([f"{j + 1}. {problem}" for j, problem in enumerate(collated_strings)])
|
|
283
332
|
|
|
284
333
|
# Add the row to the table
|
|
285
|
-
table.add_row(
|
|
334
|
+
table.add_row(library_name_with_details, problems)
|
|
286
335
|
|
|
287
336
|
# Create a panel containing the table
|
|
288
337
|
panel = Panel(table, title="Library Information", border_style="blue")
|
|
@@ -404,9 +453,7 @@ class LibraryManager:
|
|
|
404
453
|
library_path=file_path,
|
|
405
454
|
library_name=None,
|
|
406
455
|
status=LibraryStatus.MISSING,
|
|
407
|
-
problems=[
|
|
408
|
-
"Library could not be found at the file path specified. It will be removed from the configuration."
|
|
409
|
-
],
|
|
456
|
+
problems=[LibraryNotFoundProblem(library_path=str(json_path))],
|
|
410
457
|
result_details=details,
|
|
411
458
|
)
|
|
412
459
|
|
|
@@ -421,7 +468,7 @@ class LibraryManager:
|
|
|
421
468
|
library_path=file_path,
|
|
422
469
|
library_name=None,
|
|
423
470
|
status=LibraryStatus.UNUSABLE,
|
|
424
|
-
problems=[
|
|
471
|
+
problems=[LibraryJsonDecodeProblem()],
|
|
425
472
|
result_details=details,
|
|
426
473
|
)
|
|
427
474
|
except Exception as err:
|
|
@@ -431,7 +478,7 @@ class LibraryManager:
|
|
|
431
478
|
library_path=file_path,
|
|
432
479
|
library_name=None,
|
|
433
480
|
status=LibraryStatus.UNUSABLE,
|
|
434
|
-
problems=[
|
|
481
|
+
problems=[LibraryLoadExceptionProblem(error_message=str(err))],
|
|
435
482
|
result_details=details,
|
|
436
483
|
)
|
|
437
484
|
|
|
@@ -448,7 +495,7 @@ class LibraryManager:
|
|
|
448
495
|
loc = " -> ".join(map(str, error["loc"]))
|
|
449
496
|
msg = error["msg"]
|
|
450
497
|
error_type = error["type"]
|
|
451
|
-
problem =
|
|
498
|
+
problem = LibrarySchemaValidationProblem(location=loc, error_type=error_type, message=msg)
|
|
452
499
|
problems.append(problem)
|
|
453
500
|
details = f"Attempted to load Library JSON file. Failed because the file at path '{json_path}' failed to match the library schema due to: {err}"
|
|
454
501
|
logger.error(details)
|
|
@@ -466,7 +513,7 @@ class LibraryManager:
|
|
|
466
513
|
library_path=file_path,
|
|
467
514
|
library_name=library_name,
|
|
468
515
|
status=LibraryStatus.UNUSABLE,
|
|
469
|
-
problems=[
|
|
516
|
+
problems=[LibrarySchemaExceptionProblem(error_message=str(err))],
|
|
470
517
|
result_details=details,
|
|
471
518
|
)
|
|
472
519
|
|
|
@@ -537,7 +584,7 @@ class LibraryManager:
|
|
|
537
584
|
library_path=sandbox_library_dir_as_posix,
|
|
538
585
|
library_name=LibraryManager.SANDBOX_LIBRARY_NAME,
|
|
539
586
|
status=LibraryStatus.MISSING,
|
|
540
|
-
problems=[
|
|
587
|
+
problems=[SandboxDirectoryMissingProblem()],
|
|
541
588
|
result_details=ResultDetails(message=details, level=logging.INFO),
|
|
542
589
|
)
|
|
543
590
|
|
|
@@ -594,7 +641,7 @@ class LibraryManager:
|
|
|
594
641
|
library_path=sandbox_library_dir_as_posix,
|
|
595
642
|
library_name=LibraryManager.SANDBOX_LIBRARY_NAME,
|
|
596
643
|
status=LibraryStatus.UNUSABLE,
|
|
597
|
-
problems=[
|
|
644
|
+
problems=[EngineVersionErrorProblem()],
|
|
598
645
|
result_details=details,
|
|
599
646
|
)
|
|
600
647
|
|
|
@@ -629,8 +676,6 @@ class LibraryManager:
|
|
|
629
676
|
library = LibraryRegistry.get_library(name=request.library)
|
|
630
677
|
except KeyError:
|
|
631
678
|
details = f"Attempted to get node metadata for a node type '{request.node_type}' in a Library named '{request.library}'. Failed because no Library with that name was registered."
|
|
632
|
-
logger.error(details)
|
|
633
|
-
|
|
634
679
|
result = GetNodeMetadataFromLibraryResultFailure(result_details=details)
|
|
635
680
|
return result
|
|
636
681
|
|
|
@@ -639,8 +684,6 @@ class LibraryManager:
|
|
|
639
684
|
metadata = library.get_node_metadata(node_type=request.node_type)
|
|
640
685
|
except KeyError:
|
|
641
686
|
details = f"Attempted to get node metadata for a node type '{request.node_type}' in a Library named '{request.library}'. Failed because no node type of that name could be found in the Library."
|
|
642
|
-
logger.error(details)
|
|
643
|
-
|
|
644
687
|
result = GetNodeMetadataFromLibraryResultFailure(result_details=details)
|
|
645
688
|
return result
|
|
646
689
|
|
|
@@ -680,9 +723,7 @@ class LibraryManager:
|
|
|
680
723
|
library_path=file_path,
|
|
681
724
|
library_name=None,
|
|
682
725
|
status=LibraryStatus.MISSING,
|
|
683
|
-
problems=[
|
|
684
|
-
"Library could not be found at the file path specified. It will be removed from the configuration."
|
|
685
|
-
],
|
|
726
|
+
problems=[LibraryNotFoundProblem(library_path=file_path)],
|
|
686
727
|
)
|
|
687
728
|
details = f"Attempted to load Library JSON file. Failed because no file could be found at the specified path: {json_path}"
|
|
688
729
|
logger.error(details)
|
|
@@ -714,9 +755,7 @@ class LibraryManager:
|
|
|
714
755
|
library_path=file_path,
|
|
715
756
|
library_name=library_data.name,
|
|
716
757
|
status=LibraryStatus.UNUSABLE,
|
|
717
|
-
problems=[
|
|
718
|
-
f"Library's version string '{library_data.metadata.library_version}' wasn't valid. Must be in major.minor.patch format."
|
|
719
|
-
],
|
|
758
|
+
problems=[InvalidVersionStringProblem(version_string=str(library_data.metadata.library_version))],
|
|
720
759
|
)
|
|
721
760
|
details = f"Attempted to load Library '{library_data.name}' JSON file from '{json_path}'. Failed because version string '{library_data.metadata.library_version}' wasn't valid. Must be in major.minor.patch format."
|
|
722
761
|
logger.error(details)
|
|
@@ -742,7 +781,9 @@ class LibraryManager:
|
|
|
742
781
|
library_version=library_version,
|
|
743
782
|
status=LibraryStatus.UNUSABLE,
|
|
744
783
|
problems=[
|
|
745
|
-
|
|
784
|
+
AdvancedLibraryLoadFailureProblem(
|
|
785
|
+
advanced_library_path=library_data.advanced_library_path, error_message=str(err)
|
|
786
|
+
)
|
|
746
787
|
],
|
|
747
788
|
)
|
|
748
789
|
details = f"Attempted to load Library '{library_data.name}' from '{json_path}'. Failed to load Advanced Library module: {err}"
|
|
@@ -765,9 +806,7 @@ class LibraryManager:
|
|
|
765
806
|
library_name=library_data.name,
|
|
766
807
|
library_version=library_version,
|
|
767
808
|
status=LibraryStatus.UNUSABLE,
|
|
768
|
-
problems=[
|
|
769
|
-
"Failed because a library with this name was already registered. Check the Settings to ensure duplicate libraries are not being loaded."
|
|
770
|
-
],
|
|
809
|
+
problems=[DuplicateLibraryProblem()],
|
|
771
810
|
)
|
|
772
811
|
|
|
773
812
|
details = f"Attempted to load Library JSON file from '{json_path}'. Failed because a Library '{library_data.name}' already exists. Error: {err}."
|
|
@@ -794,7 +833,7 @@ class LibraryManager:
|
|
|
794
833
|
library_name=library_data.name,
|
|
795
834
|
library_version=library_version,
|
|
796
835
|
status=LibraryStatus.UNUSABLE,
|
|
797
|
-
problems=[str(e)],
|
|
836
|
+
problems=[VenvCreationFailedProblem(error_message=str(e))],
|
|
798
837
|
)
|
|
799
838
|
details = f"Attempted to load Library JSON file from '{json_path}'. Failed when creating the virtual environment: {e}."
|
|
800
839
|
logger.error(details)
|
|
@@ -812,9 +851,7 @@ class LibraryManager:
|
|
|
812
851
|
library_name=library_data.name,
|
|
813
852
|
library_version=library_version,
|
|
814
853
|
status=LibraryStatus.UNUSABLE,
|
|
815
|
-
problems=[
|
|
816
|
-
f"Insufficient disk space for dependencies (requires {min_space_gb} GB): {error_msg}"
|
|
817
|
-
],
|
|
854
|
+
problems=[InsufficientDiskSpaceProblem(min_space_gb=min_space_gb, error_message=error_msg)],
|
|
818
855
|
)
|
|
819
856
|
return RegisterLibraryFromFileResultFailure(result_details=details)
|
|
820
857
|
|
|
@@ -854,7 +891,7 @@ class LibraryManager:
|
|
|
854
891
|
library_name=library_data.name,
|
|
855
892
|
library_version=library_version,
|
|
856
893
|
status=LibraryStatus.UNUSABLE,
|
|
857
|
-
problems=[
|
|
894
|
+
problems=[DependencyInstallationFailedProblem(error_details=error_details)],
|
|
858
895
|
)
|
|
859
896
|
details = f"Attempted to load Library JSON file from '{json_path}'. Failed when installing dependencies: {error_details}"
|
|
860
897
|
logger.error(details)
|
|
@@ -878,7 +915,7 @@ class LibraryManager:
|
|
|
878
915
|
)
|
|
879
916
|
create_new_category_result = GriptapeNodes.handle_request(create_new_category_request)
|
|
880
917
|
if not isinstance(create_new_category_result, SetConfigCategoryResultSuccess):
|
|
881
|
-
problems.append(
|
|
918
|
+
problems.append(CreateConfigCategoryProblem(category_name=library_data_setting.category))
|
|
882
919
|
details = f"Failed attempting to create new config category '{library_data_setting.category}' for library '{library_data.name}'."
|
|
883
920
|
logger.error(details)
|
|
884
921
|
continue # SKIP IT
|
|
@@ -892,7 +929,7 @@ class LibraryManager:
|
|
|
892
929
|
)
|
|
893
930
|
set_category_result = GriptapeNodes.handle_request(set_category_request)
|
|
894
931
|
if not isinstance(set_category_result, SetConfigCategoryResultSuccess):
|
|
895
|
-
problems.append(
|
|
932
|
+
problems.append(UpdateConfigCategoryProblem(category_name=library_data_setting.category))
|
|
896
933
|
details = f"Failed attempting to update config category '{library_data_setting.category}' for library '{library_data.name}'."
|
|
897
934
|
logger.error(details)
|
|
898
935
|
continue # SKIP IT
|
|
@@ -1394,6 +1431,21 @@ class LibraryManager:
|
|
|
1394
1431
|
"""
|
|
1395
1432
|
return module_name.startswith("gtn_dynamic_module_")
|
|
1396
1433
|
|
|
1434
|
+
@staticmethod
|
|
1435
|
+
def _get_root_cause_from_exception(exception: BaseException) -> BaseException:
|
|
1436
|
+
"""Walk the exception chain to find the root cause.
|
|
1437
|
+
|
|
1438
|
+
Args:
|
|
1439
|
+
exception: The exception to walk
|
|
1440
|
+
|
|
1441
|
+
Returns:
|
|
1442
|
+
The root cause exception (the innermost exception in the chain)
|
|
1443
|
+
"""
|
|
1444
|
+
current = exception
|
|
1445
|
+
while current.__cause__ is not None:
|
|
1446
|
+
current = current.__cause__
|
|
1447
|
+
return current
|
|
1448
|
+
|
|
1397
1449
|
def _load_module_from_file(self, file_path: Path | str, library_name: str) -> ModuleType:
|
|
1398
1450
|
"""Dynamically load a module from a Python file with support for hot reloading.
|
|
1399
1451
|
|
|
@@ -1532,13 +1584,44 @@ class LibraryManager:
|
|
|
1532
1584
|
problems=failed_library.problems,
|
|
1533
1585
|
)
|
|
1534
1586
|
|
|
1587
|
+
# Calculate total libraries for progress tracking
|
|
1588
|
+
total_libraries = len(metadata_result.successful_libraries)
|
|
1589
|
+
|
|
1535
1590
|
# Use metadata results to selectively load libraries
|
|
1536
|
-
for library_result in metadata_result.successful_libraries:
|
|
1591
|
+
for current_library_index, library_result in enumerate(metadata_result.successful_libraries, start=1):
|
|
1592
|
+
library_name = library_result.library_schema.name
|
|
1593
|
+
|
|
1594
|
+
# Emit loading event
|
|
1595
|
+
GriptapeNodes.EventManager().put_event(
|
|
1596
|
+
AppEvent(
|
|
1597
|
+
payload=EngineInitializationProgress(
|
|
1598
|
+
phase=InitializationPhase.LIBRARIES,
|
|
1599
|
+
item_name=library_name,
|
|
1600
|
+
status=InitializationStatus.LOADING,
|
|
1601
|
+
current=current_library_index,
|
|
1602
|
+
total=total_libraries,
|
|
1603
|
+
)
|
|
1604
|
+
)
|
|
1605
|
+
)
|
|
1606
|
+
|
|
1607
|
+
# Register the library
|
|
1537
1608
|
if library_result.library_schema.name == LibraryManager.SANDBOX_LIBRARY_NAME:
|
|
1538
1609
|
# Handle sandbox library - use the schema we already have
|
|
1539
1610
|
await self._attempt_generate_sandbox_library_from_schema(
|
|
1540
1611
|
library_schema=library_result.library_schema, sandbox_directory=library_result.file_path
|
|
1541
1612
|
)
|
|
1613
|
+
# Emit success event for sandbox library
|
|
1614
|
+
GriptapeNodes.EventManager().put_event(
|
|
1615
|
+
AppEvent(
|
|
1616
|
+
payload=EngineInitializationProgress(
|
|
1617
|
+
phase=InitializationPhase.LIBRARIES,
|
|
1618
|
+
item_name=library_name,
|
|
1619
|
+
status=InitializationStatus.COMPLETE,
|
|
1620
|
+
current=current_library_index,
|
|
1621
|
+
total=total_libraries,
|
|
1622
|
+
)
|
|
1623
|
+
)
|
|
1624
|
+
)
|
|
1542
1625
|
else:
|
|
1543
1626
|
# Handle config-based library - register it directly using the file path
|
|
1544
1627
|
register_request = RegisterLibraryFromFileRequest(
|
|
@@ -1549,6 +1632,37 @@ class LibraryManager:
|
|
|
1549
1632
|
# Registration failed - the failure info is already recorded in _library_file_path_to_info
|
|
1550
1633
|
# by register_library_from_file_request, so we just log it here for visibility
|
|
1551
1634
|
logger.warning("Failed to register library from %s", library_result.file_path)
|
|
1635
|
+
# Emit failure event
|
|
1636
|
+
error_message = (
|
|
1637
|
+
register_result.result_details.result_details[0].message
|
|
1638
|
+
if isinstance(register_result.result_details, ResultDetails)
|
|
1639
|
+
else register_result.result_details
|
|
1640
|
+
)
|
|
1641
|
+
GriptapeNodes.EventManager().put_event(
|
|
1642
|
+
AppEvent(
|
|
1643
|
+
payload=EngineInitializationProgress(
|
|
1644
|
+
phase=InitializationPhase.LIBRARIES,
|
|
1645
|
+
item_name=library_name,
|
|
1646
|
+
status=InitializationStatus.FAILED,
|
|
1647
|
+
current=current_library_index,
|
|
1648
|
+
total=total_libraries,
|
|
1649
|
+
error=error_message,
|
|
1650
|
+
)
|
|
1651
|
+
)
|
|
1652
|
+
)
|
|
1653
|
+
else:
|
|
1654
|
+
# Emit success event
|
|
1655
|
+
GriptapeNodes.EventManager().put_event(
|
|
1656
|
+
AppEvent(
|
|
1657
|
+
payload=EngineInitializationProgress(
|
|
1658
|
+
phase=InitializationPhase.LIBRARIES,
|
|
1659
|
+
item_name=library_name,
|
|
1660
|
+
status=InitializationStatus.COMPLETE,
|
|
1661
|
+
current=current_library_index,
|
|
1662
|
+
total=total_libraries,
|
|
1663
|
+
)
|
|
1664
|
+
)
|
|
1665
|
+
)
|
|
1552
1666
|
|
|
1553
1667
|
# Print 'em all pretty
|
|
1554
1668
|
self.print_library_load_status()
|
|
@@ -1782,7 +1896,7 @@ class LibraryManager:
|
|
|
1782
1896
|
base_dir: Path,
|
|
1783
1897
|
library_file_path: str,
|
|
1784
1898
|
library_version: str | None,
|
|
1785
|
-
problems: list[
|
|
1899
|
+
problems: list[LibraryProblem],
|
|
1786
1900
|
) -> LibraryManager.LibraryInfo:
|
|
1787
1901
|
any_nodes_loaded_successfully = False
|
|
1788
1902
|
|
|
@@ -1790,7 +1904,7 @@ class LibraryManager:
|
|
|
1790
1904
|
version_issues = GriptapeNodes.VersionCompatibilityManager().check_library_version_compatibility(library_data)
|
|
1791
1905
|
has_disqualifying_issues = False
|
|
1792
1906
|
for issue in version_issues:
|
|
1793
|
-
problems.append(issue.
|
|
1907
|
+
problems.append(issue.problem)
|
|
1794
1908
|
if issue.severity == LibraryStatus.UNUSABLE:
|
|
1795
1909
|
has_disqualifying_issues = True
|
|
1796
1910
|
|
|
@@ -1812,8 +1926,7 @@ class LibraryManager:
|
|
|
1812
1926
|
details = f"Successfully called before_library_nodes_loaded callback for library '{library_data.name}'"
|
|
1813
1927
|
logger.debug(details)
|
|
1814
1928
|
except Exception as err:
|
|
1815
|
-
|
|
1816
|
-
problems.append(problem)
|
|
1929
|
+
problems.append(BeforeLibraryCallbackProblem(error_message=str(err)))
|
|
1817
1930
|
details = (
|
|
1818
1931
|
f"Failed to call before_library_nodes_loaded callback for library '{library_data.name}': {err}"
|
|
1819
1932
|
)
|
|
@@ -1829,27 +1942,39 @@ class LibraryManager:
|
|
|
1829
1942
|
try:
|
|
1830
1943
|
# Dynamically load the module containing the node class
|
|
1831
1944
|
node_class = self._load_class_from_file(node_file_path, node_definition.class_name, library_data.name)
|
|
1832
|
-
except
|
|
1945
|
+
except ImportError as err:
|
|
1946
|
+
root_cause = self._get_root_cause_from_exception(err)
|
|
1833
1947
|
problems.append(
|
|
1834
|
-
|
|
1948
|
+
NodeModuleImportProblem(
|
|
1949
|
+
class_name=node_definition.class_name,
|
|
1950
|
+
file_path=str(node_file_path),
|
|
1951
|
+
error_message=str(err),
|
|
1952
|
+
root_cause=str(root_cause),
|
|
1953
|
+
)
|
|
1835
1954
|
)
|
|
1836
|
-
details = f"Attempted to load node '{node_definition.class_name}' from '{node_file_path}'. Failed because
|
|
1955
|
+
details = f"Attempted to load node '{node_definition.class_name}' from '{node_file_path}'. Failed because module could not be imported: {err}"
|
|
1837
1956
|
logger.error(details)
|
|
1838
1957
|
continue # SKIP IT
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1958
|
+
except AttributeError:
|
|
1959
|
+
problems.append(
|
|
1960
|
+
NodeClassNotFoundProblem(class_name=node_definition.class_name, file_path=str(node_file_path))
|
|
1961
|
+
)
|
|
1962
|
+
details = f"Attempted to load node '{node_definition.class_name}' from '{node_file_path}'. Failed because class not found in module"
|
|
1963
|
+
logger.error(details)
|
|
1964
|
+
continue # SKIP IT
|
|
1965
|
+
except TypeError:
|
|
1846
1966
|
problems.append(
|
|
1847
|
-
|
|
1967
|
+
NodeClassNotBaseNodeProblem(class_name=node_definition.class_name, file_path=str(node_file_path))
|
|
1848
1968
|
)
|
|
1849
|
-
details = f"Attempted to load node '{node_definition.class_name}' from '{node_file_path}'. Failed because
|
|
1969
|
+
details = f"Attempted to load node '{node_definition.class_name}' from '{node_file_path}'. Failed because class doesn't inherit from BaseNode"
|
|
1850
1970
|
logger.error(details)
|
|
1851
1971
|
continue # SKIP IT
|
|
1852
1972
|
|
|
1973
|
+
# Register the node type with the library
|
|
1974
|
+
library_problem = library.register_new_node_type(node_class, metadata=node_definition.metadata)
|
|
1975
|
+
if library_problem is not None:
|
|
1976
|
+
problems.append(library_problem)
|
|
1977
|
+
|
|
1853
1978
|
# If we got here, at least one node came in.
|
|
1854
1979
|
any_nodes_loaded_successfully = True
|
|
1855
1980
|
|
|
@@ -1860,8 +1985,7 @@ class LibraryManager:
|
|
|
1860
1985
|
details = f"Successfully called after_library_nodes_loaded callback for library '{library_data.name}'"
|
|
1861
1986
|
logger.debug(details)
|
|
1862
1987
|
except Exception as err:
|
|
1863
|
-
|
|
1864
|
-
problems.append(problem)
|
|
1988
|
+
problems.append(AfterLibraryCallbackProblem(error_message=str(err)))
|
|
1865
1989
|
details = f"Failed to call after_library_nodes_loaded callback for library '{library_data.name}': {err}"
|
|
1866
1990
|
logger.error(details)
|
|
1867
1991
|
|
|
@@ -1900,7 +2024,15 @@ class LibraryManager:
|
|
|
1900
2024
|
try:
|
|
1901
2025
|
module = self._load_module_from_file(candidate_path, LibraryManager.SANDBOX_LIBRARY_NAME)
|
|
1902
2026
|
except Exception as err:
|
|
1903
|
-
|
|
2027
|
+
root_cause = self._get_root_cause_from_exception(err)
|
|
2028
|
+
problems.append(
|
|
2029
|
+
NodeModuleImportProblem(
|
|
2030
|
+
class_name=node_def.class_name,
|
|
2031
|
+
file_path=str(candidate_path),
|
|
2032
|
+
error_message=str(err),
|
|
2033
|
+
root_cause=str(root_cause),
|
|
2034
|
+
)
|
|
2035
|
+
)
|
|
1904
2036
|
details = f"Attempted to load module in sandbox library '{candidate_path}'. Failed because an exception occurred: {err}."
|
|
1905
2037
|
logger.warning(details)
|
|
1906
2038
|
continue # SKIP IT
|
|
@@ -1966,9 +2098,7 @@ class LibraryManager:
|
|
|
1966
2098
|
library_name=library_data.name,
|
|
1967
2099
|
library_version=library_data.metadata.library_version,
|
|
1968
2100
|
status=LibraryStatus.UNUSABLE,
|
|
1969
|
-
problems=[
|
|
1970
|
-
"Failed because a library with this name was already registered. Check the Settings to ensure duplicate libraries are not being loaded."
|
|
1971
|
-
],
|
|
2101
|
+
problems=[DuplicateLibraryProblem()],
|
|
1972
2102
|
)
|
|
1973
2103
|
|
|
1974
2104
|
details = f"Attempted to load Library JSON file from '{sandbox_library_dir}'. Failed because a Library '{library_data.name}' already exists. Error: {err}."
|
|
@@ -2013,7 +2143,7 @@ class LibraryManager:
|
|
|
2013
2143
|
]
|
|
2014
2144
|
config_mgr.set_config_value(config_category, libraries_to_register_category)
|
|
2015
2145
|
|
|
2016
|
-
async def
|
|
2146
|
+
async def reload_libraries_request(self, request: ReloadAllLibrariesRequest) -> ResultPayload: # noqa: ARG002
|
|
2017
2147
|
# Start with a clean slate.
|
|
2018
2148
|
clear_all_request = ClearAllObjectStateRequest(i_know_what_im_doing=True)
|
|
2019
2149
|
clear_all_result = await GriptapeNodes.ahandle_request(clear_all_request)
|
|
@@ -2046,6 +2176,25 @@ class LibraryManager:
|
|
|
2046
2176
|
)
|
|
2047
2177
|
return ReloadAllLibrariesResultSuccess(result_details=ResultDetails(message=details, level=logging.INFO))
|
|
2048
2178
|
|
|
2179
|
+
async def load_libraries_request(self, request: LoadLibrariesRequest) -> ResultPayload: # noqa: ARG002
|
|
2180
|
+
# Check if there are any new libraries in config that haven't been loaded yet
|
|
2181
|
+
discovered_libraries = {str(path) for path in self._discover_library_files()}
|
|
2182
|
+
loaded_libraries = set(self._library_file_path_to_info.keys())
|
|
2183
|
+
unloaded_libraries = discovered_libraries - loaded_libraries
|
|
2184
|
+
|
|
2185
|
+
if not unloaded_libraries:
|
|
2186
|
+
details = "All configured libraries are already loaded, no action needed."
|
|
2187
|
+
return LoadLibrariesResultSuccess(result_details=ResultDetails(message=details, level=logging.INFO))
|
|
2188
|
+
|
|
2189
|
+
try:
|
|
2190
|
+
await self.load_all_libraries_from_config()
|
|
2191
|
+
details = "Successfully loaded all libraries from configuration."
|
|
2192
|
+
return LoadLibrariesResultSuccess(result_details=ResultDetails(message=details, level=logging.INFO))
|
|
2193
|
+
except Exception as e:
|
|
2194
|
+
details = f"Failed to load libraries from configuration: {e}"
|
|
2195
|
+
logger.error(details)
|
|
2196
|
+
return LoadLibrariesResultFailure(result_details=details)
|
|
2197
|
+
|
|
2049
2198
|
def _discover_library_files(self) -> list[Path]:
|
|
2050
2199
|
"""Discover library JSON files from config and workspace recursively.
|
|
2051
2200
|
|