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.
Files changed (74) hide show
  1. griptape_nodes/cli/commands/libraries.py +6 -21
  2. griptape_nodes/drivers/thread_storage/__init__.py +15 -0
  3. griptape_nodes/drivers/thread_storage/base_thread_storage_driver.py +106 -0
  4. griptape_nodes/drivers/thread_storage/griptape_cloud_thread_storage_driver.py +213 -0
  5. griptape_nodes/drivers/thread_storage/local_thread_storage_driver.py +137 -0
  6. griptape_nodes/drivers/thread_storage/thread_storage_backend.py +10 -0
  7. griptape_nodes/node_library/library_registry.py +16 -9
  8. griptape_nodes/node_library/workflow_registry.py +1 -1
  9. griptape_nodes/retained_mode/events/agent_events.py +232 -9
  10. griptape_nodes/retained_mode/events/app_events.py +38 -0
  11. griptape_nodes/retained_mode/events/library_events.py +32 -3
  12. griptape_nodes/retained_mode/events/os_events.py +101 -1
  13. griptape_nodes/retained_mode/managers/agent_manager.py +335 -135
  14. griptape_nodes/retained_mode/managers/fitness_problems/__init__.py +1 -0
  15. griptape_nodes/retained_mode/managers/fitness_problems/libraries/__init__.py +59 -0
  16. griptape_nodes/retained_mode/managers/fitness_problems/libraries/advanced_library_load_failure_problem.py +33 -0
  17. griptape_nodes/retained_mode/managers/fitness_problems/libraries/after_library_callback_problem.py +32 -0
  18. griptape_nodes/retained_mode/managers/fitness_problems/libraries/before_library_callback_problem.py +32 -0
  19. griptape_nodes/retained_mode/managers/fitness_problems/libraries/create_config_category_problem.py +32 -0
  20. griptape_nodes/retained_mode/managers/fitness_problems/libraries/dependency_installation_failed_problem.py +32 -0
  21. griptape_nodes/retained_mode/managers/fitness_problems/libraries/deprecated_node_warning_problem.py +83 -0
  22. griptape_nodes/retained_mode/managers/fitness_problems/libraries/duplicate_library_problem.py +28 -0
  23. griptape_nodes/retained_mode/managers/fitness_problems/libraries/duplicate_node_registration_problem.py +44 -0
  24. griptape_nodes/retained_mode/managers/fitness_problems/libraries/engine_version_error_problem.py +28 -0
  25. griptape_nodes/retained_mode/managers/fitness_problems/libraries/insufficient_disk_space_problem.py +33 -0
  26. griptape_nodes/retained_mode/managers/fitness_problems/libraries/invalid_version_string_problem.py +32 -0
  27. griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_json_decode_problem.py +28 -0
  28. griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_load_exception_problem.py +32 -0
  29. griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_not_found_problem.py +30 -0
  30. griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_problem.py +20 -0
  31. griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_schema_exception_problem.py +32 -0
  32. griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_schema_validation_problem.py +38 -0
  33. griptape_nodes/retained_mode/managers/fitness_problems/libraries/modified_parameters_set_deprecation_warning_problem.py +44 -0
  34. griptape_nodes/retained_mode/managers/fitness_problems/libraries/modified_parameters_set_removed_problem.py +44 -0
  35. griptape_nodes/retained_mode/managers/fitness_problems/libraries/node_class_not_base_node_problem.py +40 -0
  36. griptape_nodes/retained_mode/managers/fitness_problems/libraries/node_class_not_found_problem.py +38 -0
  37. griptape_nodes/retained_mode/managers/fitness_problems/libraries/node_module_import_problem.py +53 -0
  38. griptape_nodes/retained_mode/managers/fitness_problems/libraries/sandbox_directory_missing_problem.py +28 -0
  39. griptape_nodes/retained_mode/managers/fitness_problems/libraries/ui_options_field_modified_incompatible_problem.py +44 -0
  40. griptape_nodes/retained_mode/managers/fitness_problems/libraries/ui_options_field_modified_warning_problem.py +35 -0
  41. griptape_nodes/retained_mode/managers/fitness_problems/libraries/update_config_category_problem.py +32 -0
  42. griptape_nodes/retained_mode/managers/fitness_problems/libraries/venv_creation_failed_problem.py +32 -0
  43. griptape_nodes/retained_mode/managers/fitness_problems/workflows/__init__.py +75 -0
  44. griptape_nodes/retained_mode/managers/fitness_problems/workflows/deprecated_node_in_workflow_problem.py +83 -0
  45. griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_dependency_version_string_problem.py +38 -0
  46. griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_library_version_string_problem.py +38 -0
  47. griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_metadata_schema_problem.py +31 -0
  48. griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_metadata_section_count_problem.py +31 -0
  49. griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_toml_format_problem.py +30 -0
  50. griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_not_registered_problem.py +35 -0
  51. griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_below_required_problem.py +41 -0
  52. griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_large_difference_problem.py +41 -0
  53. griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_major_mismatch_problem.py +41 -0
  54. griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_minor_difference_problem.py +41 -0
  55. griptape_nodes/retained_mode/managers/fitness_problems/workflows/missing_creation_date_problem.py +30 -0
  56. griptape_nodes/retained_mode/managers/fitness_problems/workflows/missing_last_modified_date_problem.py +30 -0
  57. griptape_nodes/retained_mode/managers/fitness_problems/workflows/missing_toml_section_problem.py +30 -0
  58. griptape_nodes/retained_mode/managers/fitness_problems/workflows/node_type_not_found_problem.py +51 -0
  59. griptape_nodes/retained_mode/managers/fitness_problems/workflows/workflow_not_found_problem.py +27 -0
  60. griptape_nodes/retained_mode/managers/fitness_problems/workflows/workflow_problem.py +20 -0
  61. griptape_nodes/retained_mode/managers/fitness_problems/workflows/workflow_schema_version_problem.py +39 -0
  62. griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +17 -3
  63. griptape_nodes/retained_mode/managers/library_manager.py +226 -77
  64. griptape_nodes/retained_mode/managers/os_manager.py +172 -1
  65. griptape_nodes/retained_mode/managers/settings.py +5 -0
  66. griptape_nodes/retained_mode/managers/version_compatibility_manager.py +76 -51
  67. griptape_nodes/retained_mode/managers/workflow_manager.py +237 -159
  68. griptape_nodes/servers/static.py +18 -19
  69. griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +16 -12
  70. griptape_nodes/version_compatibility/workflow_versions/v0_7_0/local_executor_argument_addition.py +6 -3
  71. {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/METADATA +2 -1
  72. {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/RECORD +74 -21
  73. {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/WHEEL +0 -0
  74. {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class BeforeLibraryCallbackProblem(LibraryProblem):
13
+ """Problem indicating an error calling the before_library_nodes_loaded callback."""
14
+
15
+ error_message: str
16
+
17
+ @classmethod
18
+ def collate_problems_for_display(cls, instances: list[BeforeLibraryCallbackProblem]) -> str:
19
+ """Display before library callback problem.
20
+
21
+ There should only be one instance per library since there's only one
22
+ before_library_nodes_loaded callback per library.
23
+ """
24
+ if len(instances) > 1:
25
+ logger.error(
26
+ "BeforeLibraryCallbackProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one BeforeLibraryCallbackProblem.",
27
+ len(instances),
28
+ )
29
+
30
+ # Use the first instance's error message
31
+ error_msg = instances[0].error_message
32
+ return f"Error calling before_library_nodes_loaded callback: {error_msg}"
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class CreateConfigCategoryProblem(LibraryProblem):
13
+ """Problem indicating a config category failed to be created."""
14
+
15
+ category_name: str
16
+
17
+ @classmethod
18
+ def collate_problems_for_display(cls, instances: list[CreateConfigCategoryProblem]) -> str:
19
+ """Display config category creation problem.
20
+
21
+ There should only be one instance per library since each LibraryInfo
22
+ is already associated with a specific library path.
23
+ """
24
+ if len(instances) > 1:
25
+ logger.error(
26
+ "CreateConfigCategoryProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one CreateConfigCategoryProblem.",
27
+ len(instances),
28
+ )
29
+
30
+ # Use the first instance's category name
31
+ category = instances[0].category_name
32
+ return f"Failed to create new config category '{category}'."
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class DependencyInstallationFailedProblem(LibraryProblem):
13
+ """Problem indicating dependency installation failed."""
14
+
15
+ error_details: str
16
+
17
+ @classmethod
18
+ def collate_problems_for_display(cls, instances: list[DependencyInstallationFailedProblem]) -> str:
19
+ """Display dependency installation failed problem.
20
+
21
+ There should only be one instance per library since each LibraryInfo
22
+ is already associated with a specific library path.
23
+ """
24
+ if len(instances) > 1:
25
+ logger.error(
26
+ "DependencyInstallationFailedProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one DependencyInstallationFailedProblem.",
27
+ len(instances),
28
+ )
29
+
30
+ # Use the first instance's error details
31
+ details = instances[0].error_details
32
+ return f"Dependency installation failed: {details}"
@@ -0,0 +1,83 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from collections import defaultdict
5
+ from dataclasses import dataclass
6
+
7
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ @dataclass
13
+ class DeprecatedNodeWarningProblem(LibraryProblem):
14
+ """Problem indicating a library contains deprecated nodes.
15
+
16
+ This is stackable - multiple nodes can be deprecated.
17
+ """
18
+
19
+ display_name: str
20
+ class_name: str
21
+ removal_version: str | None
22
+ deprecation_message: str | None
23
+
24
+ @classmethod
25
+ def collate_problems_for_display(cls, instances: list[DeprecatedNodeWarningProblem]) -> str:
26
+ """Display deprecated node warnings.
27
+
28
+ Groups by removal version, then lists nodes within each group.
29
+ """
30
+ if len(instances) == 1:
31
+ problem = instances[0]
32
+ removal_info = (
33
+ f"will be removed in version {problem.removal_version}"
34
+ if problem.removal_version
35
+ else "may be removed in future versions"
36
+ )
37
+ message = f"Node '{problem.display_name}' is deprecated and {removal_info}."
38
+ if problem.deprecation_message:
39
+ message += f" {problem.deprecation_message}"
40
+ return message
41
+
42
+ # Group by removal version
43
+ by_version = defaultdict(list)
44
+ for problem in instances:
45
+ by_version[problem.removal_version].append(problem)
46
+
47
+ # Sort versions (None comes last)
48
+ sorted_versions = sorted(by_version.keys(), key=lambda v: (v is None, v or ""))
49
+
50
+ output_lines = []
51
+ output_lines.append(f"Encountered {len(instances)} deprecated nodes:")
52
+
53
+ for version in sorted_versions:
54
+ nodes = by_version[version]
55
+
56
+ if version is None:
57
+ output_lines.append(" Nodes that may be removed in future versions:")
58
+ else:
59
+ output_lines.append(f" Nodes to be removed in version {version}:")
60
+
61
+ # Group nodes within this version by deprecation_message
62
+ by_message = defaultdict(list)
63
+ for node in nodes:
64
+ # Use empty string as key if no message
65
+ message_key = node.deprecation_message if node.deprecation_message else ""
66
+ by_message[message_key].append(node)
67
+
68
+ # Sort messages alphabetically (empty string first)
69
+ sorted_messages = sorted(by_message.keys(), key=lambda m: (m != "", m))
70
+
71
+ for message in sorted_messages:
72
+ message_nodes = by_message[message]
73
+ # Sort nodes by display_name within each message group
74
+ message_nodes.sort(key=lambda p: p.display_name)
75
+
76
+ if message:
77
+ output_lines.append(f" {message}:")
78
+ output_lines.extend(f" - {node.display_name}" for node in message_nodes)
79
+ else:
80
+ # No deprecation message provided
81
+ output_lines.extend(f" - {node.display_name}" for node in message_nodes)
82
+
83
+ return "\n".join(output_lines)
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class DuplicateLibraryProblem(LibraryProblem):
13
+ """Problem indicating a library with this name was already registered."""
14
+
15
+ @classmethod
16
+ def collate_problems_for_display(cls, instances: list[DuplicateLibraryProblem]) -> str:
17
+ """Display duplicate library problem.
18
+
19
+ There should only be one instance per library since each LibraryInfo
20
+ is already associated with a specific library path.
21
+ """
22
+ if len(instances) > 1:
23
+ logger.error(
24
+ "DuplicateLibraryProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one DuplicateLibraryProblem.",
25
+ len(instances),
26
+ )
27
+
28
+ return "Failed because a library with this name was already registered. Check the Settings to ensure duplicate libraries are not being loaded."
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class DuplicateNodeRegistrationProblem(LibraryProblem):
13
+ """Problem indicating a node class was already registered.
14
+
15
+ This is stackable - multiple duplicate registrations can occur.
16
+ """
17
+
18
+ class_name: str
19
+ library_name: str
20
+
21
+ @classmethod
22
+ def collate_problems_for_display(cls, instances: list[DuplicateNodeRegistrationProblem]) -> str:
23
+ """Display duplicate node registration problems.
24
+
25
+ Can handle multiple duplicates - they will be listed out sorted by class_name.
26
+ """
27
+ if len(instances) == 1:
28
+ problem = instances[0]
29
+ return (
30
+ f"Attempted to register node class '{problem.class_name}' from library '{problem.library_name}', "
31
+ f"but a node with that name from that library was already registered. "
32
+ "Check to ensure you aren't re-adding the same libraries multiple times."
33
+ )
34
+
35
+ # Multiple duplicate registrations - list them sorted by class_name
36
+ sorted_instances = sorted(instances, key=lambda p: p.class_name)
37
+ error_lines = []
38
+ for i, problem in enumerate(sorted_instances, 1):
39
+ error_lines.append(
40
+ f" {i}. Node '{problem.class_name}' from library '{problem.library_name}' already registered"
41
+ )
42
+
43
+ header = f"Encountered {len(instances)} duplicate node registrations:"
44
+ return header + "\n" + "\n".join(error_lines)
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class EngineVersionErrorProblem(LibraryProblem):
13
+ """Problem indicating the engine version could not be retrieved for sandbox library generation."""
14
+
15
+ @classmethod
16
+ def collate_problems_for_display(cls, instances: list[EngineVersionErrorProblem]) -> str:
17
+ """Display engine version error problem.
18
+
19
+ There should only be one instance per library since each LibraryInfo
20
+ is already associated with a specific library path.
21
+ """
22
+ if len(instances) > 1:
23
+ logger.error(
24
+ "EngineVersionErrorProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one EngineVersionErrorProblem.",
25
+ len(instances),
26
+ )
27
+
28
+ return "Could not get engine version for sandbox library generation."
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class InsufficientDiskSpaceProblem(LibraryProblem):
13
+ """Problem indicating insufficient disk space for dependencies."""
14
+
15
+ min_space_gb: float
16
+ error_message: str
17
+
18
+ @classmethod
19
+ def collate_problems_for_display(cls, instances: list[InsufficientDiskSpaceProblem]) -> str:
20
+ """Display insufficient disk space problem.
21
+
22
+ There should only be one instance per library since each LibraryInfo
23
+ is already associated with a specific library path.
24
+ """
25
+ if len(instances) > 1:
26
+ logger.error(
27
+ "InsufficientDiskSpaceProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one InsufficientDiskSpaceProblem.",
28
+ len(instances),
29
+ )
30
+
31
+ # Use the first instance's details
32
+ problem = instances[0]
33
+ return f"Insufficient disk space for dependencies (requires {problem.min_space_gb} GB): {problem.error_message}"
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class InvalidVersionStringProblem(LibraryProblem):
13
+ """Problem indicating a library's version string is not valid (must be major.minor.patch format)."""
14
+
15
+ version_string: str
16
+
17
+ @classmethod
18
+ def collate_problems_for_display(cls, instances: list[InvalidVersionStringProblem]) -> str:
19
+ """Display invalid version string problem.
20
+
21
+ There should only be one instance per library since each LibraryInfo
22
+ is already associated with a specific library path.
23
+ """
24
+ if len(instances) > 1:
25
+ logger.error(
26
+ "InvalidVersionStringProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one InvalidVersionStringProblem.",
27
+ len(instances),
28
+ )
29
+
30
+ # Use the first instance's version string
31
+ version = instances[0].version_string
32
+ return f"Library's version string '{version}' wasn't valid. Must be in major.minor.patch format."
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class LibraryJsonDecodeProblem(LibraryProblem):
13
+ """Problem indicating a library file is not properly formatted JSON."""
14
+
15
+ @classmethod
16
+ def collate_problems_for_display(cls, instances: list[LibraryJsonDecodeProblem]) -> str:
17
+ """Display library JSON decode problem.
18
+
19
+ There should only be one instance per library since each LibraryInfo
20
+ is already associated with a specific library path.
21
+ """
22
+ if len(instances) > 1:
23
+ logger.error(
24
+ "LibraryJsonDecodeProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one LibraryJsonDecodeProblem.",
25
+ len(instances),
26
+ )
27
+
28
+ return "Library file not formatted as proper JSON."
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class LibraryLoadExceptionProblem(LibraryProblem):
13
+ """Problem indicating an exception occurred while loading the library file."""
14
+
15
+ error_message: str
16
+
17
+ @classmethod
18
+ def collate_problems_for_display(cls, instances: list[LibraryLoadExceptionProblem]) -> str:
19
+ """Display library load exception problem.
20
+
21
+ There should only be one instance per library since each LibraryInfo
22
+ is already associated with a specific library path.
23
+ """
24
+ if len(instances) > 1:
25
+ logger.error(
26
+ "LibraryLoadExceptionProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one LibraryLoadExceptionProblem.",
27
+ len(instances),
28
+ )
29
+
30
+ # Use the first instance's error message
31
+ error_msg = instances[0].error_message
32
+ return f"Exception occurred when attempting to load the library: {error_msg}."
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class LibraryNotFoundProblem(LibraryProblem):
13
+ """Problem indicating a library file could not be found at the specified path."""
14
+
15
+ library_path: str
16
+
17
+ @classmethod
18
+ def collate_problems_for_display(cls, instances: list[LibraryNotFoundProblem]) -> str:
19
+ """Display library not found problem.
20
+
21
+ There should only be one instance per library since each LibraryInfo
22
+ is already associated with a specific library path.
23
+ """
24
+ if len(instances) > 1:
25
+ logger.error(
26
+ "LibraryNotFoundProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one LibraryNotFoundProblem.",
27
+ len(instances),
28
+ )
29
+
30
+ return "Library could not be found at the file path specified. It will be removed from the configuration."
@@ -0,0 +1,20 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Self
3
+
4
+
5
+ class LibraryProblem(ABC):
6
+ """Base class for all library fitness problems."""
7
+
8
+ @classmethod
9
+ @abstractmethod
10
+ def collate_problems_for_display(cls, instances: list[Self]) -> str:
11
+ """Display one or more instances of this problem type.
12
+
13
+ Handles both single and multiple instances with appropriate formatting.
14
+
15
+ Args:
16
+ instances: List of problem instances of this type to display.
17
+
18
+ Returns:
19
+ Formatted string describing the problem(s).
20
+ """
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class LibrarySchemaExceptionProblem(LibraryProblem):
13
+ """Problem indicating an unexpected exception during schema validation."""
14
+
15
+ error_message: str
16
+
17
+ @classmethod
18
+ def collate_problems_for_display(cls, instances: list[LibrarySchemaExceptionProblem]) -> str:
19
+ """Display library schema exception problem.
20
+
21
+ There should only be one instance per library since each LibraryInfo
22
+ is already associated with a specific library path.
23
+ """
24
+ if len(instances) > 1:
25
+ logger.error(
26
+ "LibrarySchemaExceptionProblem: Expected 1 instance but got %s. Each LibraryInfo should only have one LibrarySchemaExceptionProblem.",
27
+ len(instances),
28
+ )
29
+
30
+ # Use the first instance's error message
31
+ error_msg = instances[0].error_message
32
+ return f"Library file did not match the library schema specified due to: {error_msg}"
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class LibrarySchemaValidationProblem(LibraryProblem):
13
+ """Problem indicating a library schema validation error.
14
+
15
+ This is stackable - multiple validation errors can occur when validating a library schema.
16
+ """
17
+
18
+ location: str
19
+ error_type: str
20
+ message: str
21
+
22
+ @classmethod
23
+ def collate_problems_for_display(cls, instances: list[LibrarySchemaValidationProblem]) -> str:
24
+ """Display library schema validation problems.
25
+
26
+ Can handle multiple validation errors - they will be listed out.
27
+ """
28
+ if len(instances) == 1:
29
+ problem = instances[0]
30
+ return f"Error in section '{problem.location}': {problem.error_type}, {problem.message}"
31
+
32
+ # Multiple validation errors - list them
33
+ error_lines = []
34
+ for i, problem in enumerate(instances, 1):
35
+ error_lines.append(f" {i}. Error in section '{problem.location}': {problem.error_type}, {problem.message}")
36
+
37
+ header = f"Encountered {len(instances)} schema validation errors:"
38
+ return header + "\n" + "\n".join(error_lines)
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class ModifiedParametersSetDeprecationWarningProblem(LibraryProblem):
13
+ """Problem warning that a library will be incompatible in the next version due to modified_parameters_set removal.
14
+
15
+ This is stackable - multiple libraries can have this warning.
16
+ This severity is FLAWED - the library can be loaded but has warnings.
17
+ """
18
+
19
+ library_engine_version: str
20
+
21
+ @classmethod
22
+ def collate_problems_for_display(cls, instances: list[ModifiedParametersSetDeprecationWarningProblem]) -> str:
23
+ """Display modified_parameters_set deprecation warnings.
24
+
25
+ Can handle multiple instances - they will be listed out sorted by library_engine_version.
26
+ """
27
+ if len(instances) == 1:
28
+ version = instances[0].library_engine_version
29
+ return (
30
+ f"WARNING: The 'modified_parameters_set' parameter will be removed in Griptape Nodes 0.39 from BaseNode methods: 'after_incoming_connection', 'after_outgoing_connection', 'after_incoming_connection_removed', 'after_outgoing_connection_removed', 'before_value_set', and 'after_value_set'. "
31
+ f"This library (built for engine version {version}) must be updated before the 0.39 release. "
32
+ "If this library overrides any of these methods, it will fail to load in 0.39. If not, no action is necessary. Please contact the library author to confirm whether this library is impacted."
33
+ )
34
+
35
+ # Multiple libraries with this warning - list them sorted by version
36
+ sorted_instances = sorted(instances, key=lambda p: p.library_engine_version)
37
+ error_lines = []
38
+ for i, problem in enumerate(sorted_instances, 1):
39
+ error_lines.append(
40
+ f" {i}. Library built for engine version {problem.library_engine_version} may be impacted by upcoming modified_parameters_set removal"
41
+ )
42
+
43
+ header = f"Encountered {len(instances)} libraries with modified_parameters_set deprecation warnings:"
44
+ return header + "\n" + "\n".join(error_lines)
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class ModifiedParametersSetRemovedProblem(LibraryProblem):
13
+ """Problem indicating a library is incompatible due to modified_parameters_set removal.
14
+
15
+ This is stackable - multiple libraries can have this issue.
16
+ This severity is UNUSABLE - the library cannot be loaded.
17
+ """
18
+
19
+ library_engine_version: str
20
+
21
+ @classmethod
22
+ def collate_problems_for_display(cls, instances: list[ModifiedParametersSetRemovedProblem]) -> str:
23
+ """Display modified_parameters_set removal problems.
24
+
25
+ Can handle multiple instances - they will be listed out sorted by library_engine_version.
26
+ """
27
+ if len(instances) == 1:
28
+ version = instances[0].library_engine_version
29
+ return (
30
+ f"This library (built for engine version {version}) is incompatible with Griptape Nodes 0.39+. "
31
+ "The 'modified_parameters_set' parameter has been removed from BaseNode methods: 'after_incoming_connection', 'after_outgoing_connection', 'after_incoming_connection_removed', 'after_outgoing_connection_removed', 'before_value_set', and 'after_value_set'. "
32
+ "If this library overrides any of these methods, it will not load or function properly. Please update to a newer version of this library or contact the library author immediately."
33
+ )
34
+
35
+ # Multiple libraries with this issue - list them sorted by version
36
+ sorted_instances = sorted(instances, key=lambda p: p.library_engine_version)
37
+ error_lines = []
38
+ for i, problem in enumerate(sorted_instances, 1):
39
+ error_lines.append(
40
+ f" {i}. Library built for engine version {problem.library_engine_version} is incompatible due to modified_parameters_set removal"
41
+ )
42
+
43
+ header = f"Encountered {len(instances)} libraries incompatible due to modified_parameters_set removal:"
44
+ return header + "\n" + "\n".join(error_lines)
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from dataclasses import dataclass
5
+
6
+ from griptape_nodes.retained_mode.managers.fitness_problems.libraries.library_problem import LibraryProblem
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @dataclass
12
+ class NodeClassNotBaseNodeProblem(LibraryProblem):
13
+ """Problem indicating a node class doesn't inherit from BaseNode.
14
+
15
+ This is stackable - multiple node classes can have incorrect inheritance.
16
+ """
17
+
18
+ class_name: str
19
+ file_path: str
20
+
21
+ @classmethod
22
+ def collate_problems_for_display(cls, instances: list[NodeClassNotBaseNodeProblem]) -> str:
23
+ """Display node class inheritance problems.
24
+
25
+ Can handle multiple non-BaseNode classes - they will be listed out sorted by class_name.
26
+ """
27
+ if len(instances) == 1:
28
+ problem = instances[0]
29
+ return f"Class '{problem.class_name}' from {problem.file_path} must inherit from BaseNode"
30
+
31
+ # Multiple inheritance issues - list them sorted by class_name
32
+ sorted_instances = sorted(instances, key=lambda p: p.class_name)
33
+ error_lines = []
34
+ for i, problem in enumerate(sorted_instances, 1):
35
+ error_lines.append(
36
+ f" {i}. Class '{problem.class_name}' from {problem.file_path} must inherit from BaseNode"
37
+ )
38
+
39
+ header = f"Encountered {len(instances)} node classes that don't inherit from BaseNode:"
40
+ return header + "\n" + "\n".join(error_lines)