griptape-nodes 0.65.5__py3-none-any.whl → 0.66.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/common/node_executor.py +352 -27
- griptape_nodes/drivers/storage/base_storage_driver.py +12 -3
- griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +18 -2
- griptape_nodes/drivers/storage/local_storage_driver.py +42 -5
- griptape_nodes/exe_types/base_iterative_nodes.py +0 -1
- griptape_nodes/exe_types/connections.py +42 -0
- griptape_nodes/exe_types/core_types.py +2 -2
- griptape_nodes/exe_types/node_groups/__init__.py +2 -1
- griptape_nodes/exe_types/node_groups/base_iterative_node_group.py +177 -0
- griptape_nodes/exe_types/node_groups/base_node_group.py +1 -0
- griptape_nodes/exe_types/node_groups/subflow_node_group.py +35 -2
- griptape_nodes/exe_types/param_types/parameter_audio.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_bool.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_button.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_float.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_image.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_int.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_number.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_string.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_three_d.py +1 -1
- griptape_nodes/exe_types/param_types/parameter_video.py +1 -1
- griptape_nodes/machines/control_flow.py +5 -4
- griptape_nodes/machines/dag_builder.py +121 -55
- griptape_nodes/machines/fsm.py +10 -0
- griptape_nodes/machines/parallel_resolution.py +39 -38
- griptape_nodes/machines/sequential_resolution.py +29 -3
- griptape_nodes/node_library/library_registry.py +41 -2
- griptape_nodes/retained_mode/events/library_events.py +147 -8
- griptape_nodes/retained_mode/events/os_events.py +12 -4
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/__init__.py +2 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/incompatible_requirements_problem.py +34 -0
- griptape_nodes/retained_mode/managers/flow_manager.py +133 -20
- griptape_nodes/retained_mode/managers/library_manager.py +1324 -564
- griptape_nodes/retained_mode/managers/node_manager.py +9 -3
- griptape_nodes/retained_mode/managers/os_manager.py +429 -65
- griptape_nodes/retained_mode/managers/resource_types/compute_resource.py +82 -0
- griptape_nodes/retained_mode/managers/resource_types/os_resource.py +17 -0
- griptape_nodes/retained_mode/managers/static_files_manager.py +21 -8
- griptape_nodes/retained_mode/managers/version_compatibility_manager.py +3 -3
- griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +5 -5
- griptape_nodes/version_compatibility/versions/v0_65_4/__init__.py +5 -0
- griptape_nodes/version_compatibility/versions/v0_65_4/run_in_parallel_to_run_in_order.py +79 -0
- griptape_nodes/version_compatibility/versions/v0_65_5/__init__.py +5 -0
- griptape_nodes/version_compatibility/versions/v0_65_5/flux_2_removed_parameters.py +85 -0
- {griptape_nodes-0.65.5.dist-info → griptape_nodes-0.66.0.dist-info}/METADATA +1 -1
- {griptape_nodes-0.65.5.dist-info → griptape_nodes-0.66.0.dist-info}/RECORD +48 -53
- griptape_nodes/retained_mode/managers/library_lifecycle/__init__.py +0 -45
- griptape_nodes/retained_mode/managers/library_lifecycle/data_models.py +0 -191
- griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +0 -346
- griptape_nodes/retained_mode/managers/library_lifecycle/library_fsm.py +0 -439
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/__init__.py +0 -17
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/base.py +0 -82
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/github.py +0 -116
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +0 -367
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/package.py +0 -104
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/sandbox.py +0 -155
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance.py +0 -18
- griptape_nodes/retained_mode/managers/library_lifecycle/library_status.py +0 -12
- {griptape_nodes-0.65.5.dist-info → griptape_nodes-0.66.0.dist-info}/WHEEL +0 -0
- {griptape_nodes-0.65.5.dist-info → griptape_nodes-0.66.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
"""Local file library provenance implementation."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
import logging
|
|
7
|
-
import os
|
|
8
|
-
import subprocess
|
|
9
|
-
import sys
|
|
10
|
-
from collections import defaultdict
|
|
11
|
-
from dataclasses import dataclass
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
from typing import TYPE_CHECKING
|
|
14
|
-
|
|
15
|
-
from pydantic import BaseModel, Field, ValidationError
|
|
16
|
-
|
|
17
|
-
from griptape_nodes.node_library.library_registry import LibraryRegistry, LibrarySchema
|
|
18
|
-
from griptape_nodes.retained_mode.events.config_events import (
|
|
19
|
-
GetConfigCategoryRequest,
|
|
20
|
-
GetConfigCategoryResultSuccess,
|
|
21
|
-
SetConfigCategoryRequest,
|
|
22
|
-
SetConfigCategoryResultSuccess,
|
|
23
|
-
)
|
|
24
|
-
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
25
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.data_models import (
|
|
26
|
-
EvaluationResult,
|
|
27
|
-
InspectionResult,
|
|
28
|
-
InstallationResult,
|
|
29
|
-
LibraryLoadedResult,
|
|
30
|
-
LifecycleIssue,
|
|
31
|
-
)
|
|
32
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.base import LibraryProvenance
|
|
33
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_status import LibraryStatus
|
|
34
|
-
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
35
|
-
from griptape_nodes.utils.async_utils import subprocess_run
|
|
36
|
-
|
|
37
|
-
if TYPE_CHECKING:
|
|
38
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_fsm import LibraryLifecycleContext
|
|
39
|
-
|
|
40
|
-
logger = logging.getLogger("griptape_nodes")
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class LibraryPreferenceLocalFile(BaseModel):
|
|
44
|
-
"""Serializable preference for a local file library."""
|
|
45
|
-
|
|
46
|
-
file_path: str = Field(description="Path to the library file")
|
|
47
|
-
active: bool = Field(default=True, description="Whether this local file library is active")
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
@dataclass(frozen=True)
|
|
51
|
-
class LibraryProvenanceLocalFile(LibraryProvenance):
|
|
52
|
-
"""Reference to a local file library."""
|
|
53
|
-
|
|
54
|
-
file_path: str
|
|
55
|
-
|
|
56
|
-
def get_display_name(self) -> str:
|
|
57
|
-
"""Get a human-readable name for this provenance."""
|
|
58
|
-
return f"Local file: {self.file_path}"
|
|
59
|
-
|
|
60
|
-
def inspect(self) -> InspectionResult:
|
|
61
|
-
"""Inspect this local file to extract schema and identify issues."""
|
|
62
|
-
issues = []
|
|
63
|
-
|
|
64
|
-
# File system validation
|
|
65
|
-
if not self._validate_file_exists():
|
|
66
|
-
issues.append(
|
|
67
|
-
LifecycleIssue(
|
|
68
|
-
message=f"Library file does not exist or is not readable: {self.file_path}",
|
|
69
|
-
severity=LibraryStatus.UNUSABLE,
|
|
70
|
-
)
|
|
71
|
-
)
|
|
72
|
-
return InspectionResult(schema=None, issues=issues)
|
|
73
|
-
|
|
74
|
-
# Schema validation
|
|
75
|
-
try:
|
|
76
|
-
with Path(self.file_path).open(encoding="utf-8") as f:
|
|
77
|
-
raw_data = json.load(f)
|
|
78
|
-
except json.JSONDecodeError as e:
|
|
79
|
-
issues.append(LifecycleIssue(message=f"Invalid JSON in library file: {e}", severity=LibraryStatus.UNUSABLE))
|
|
80
|
-
return InspectionResult(schema=None, issues=issues)
|
|
81
|
-
except Exception as e:
|
|
82
|
-
issues.append(LifecycleIssue(message=f"Failed to read library file: {e}", severity=LibraryStatus.UNUSABLE))
|
|
83
|
-
return InspectionResult(schema=None, issues=issues)
|
|
84
|
-
|
|
85
|
-
# Validate library schema structure
|
|
86
|
-
try:
|
|
87
|
-
schema = LibrarySchema.model_validate(raw_data)
|
|
88
|
-
except ValidationError as e:
|
|
89
|
-
for error in e.errors():
|
|
90
|
-
loc = " -> ".join(map(str, error["loc"]))
|
|
91
|
-
msg = error["msg"]
|
|
92
|
-
error_type = error["type"]
|
|
93
|
-
problem = f"Error in section '{loc}': {error_type}, {msg}"
|
|
94
|
-
issues.append(LifecycleIssue(message=problem, severity=LibraryStatus.UNUSABLE))
|
|
95
|
-
return InspectionResult(schema=None, issues=issues)
|
|
96
|
-
|
|
97
|
-
return InspectionResult(schema=schema, issues=issues)
|
|
98
|
-
|
|
99
|
-
def evaluate(self, context: LibraryLifecycleContext) -> EvaluationResult:
|
|
100
|
-
"""Evaluate this local file for conflicts/issues."""
|
|
101
|
-
issues = []
|
|
102
|
-
|
|
103
|
-
# Get schema from context (guaranteed to be valid at this point)
|
|
104
|
-
assert context.inspection_result is not None # noqa: S101
|
|
105
|
-
schema = context.inspection_result.schema
|
|
106
|
-
assert schema is not None # noqa: S101
|
|
107
|
-
|
|
108
|
-
# Version compatibility validation
|
|
109
|
-
version_issues = GriptapeNodes.VersionCompatibilityManager().check_library_version_compatibility(schema)
|
|
110
|
-
for issue in version_issues:
|
|
111
|
-
lifecycle_severity = LibraryStatus(issue.severity.value)
|
|
112
|
-
# Collate the problem to get the display message
|
|
113
|
-
problem_message = type(issue.problem).collate_problems_for_display([issue.problem])
|
|
114
|
-
issues.append(LifecycleIssue(message=problem_message, severity=lifecycle_severity))
|
|
115
|
-
|
|
116
|
-
# NOTE: Library name conflicts are checked at the manager level
|
|
117
|
-
# across all evaluated libraries, not here
|
|
118
|
-
|
|
119
|
-
return EvaluationResult(issues=issues)
|
|
120
|
-
|
|
121
|
-
async def install(self, context: LibraryLifecycleContext) -> InstallationResult:
|
|
122
|
-
"""Install this local file library."""
|
|
123
|
-
problems = []
|
|
124
|
-
venv_path = ""
|
|
125
|
-
|
|
126
|
-
# Get the LibraryManager instance to use its methods
|
|
127
|
-
library_manager = GriptapeNodes.LibraryManager()
|
|
128
|
-
|
|
129
|
-
# Get library schema from context (guaranteed to be valid at this point)
|
|
130
|
-
assert context.inspection_result is not None # noqa: S101
|
|
131
|
-
library_data = context.inspection_result.schema
|
|
132
|
-
assert library_data is not None # noqa: S101
|
|
133
|
-
|
|
134
|
-
# If no dependencies are specified, early out
|
|
135
|
-
if not (
|
|
136
|
-
library_data.metadata
|
|
137
|
-
and library_data.metadata.dependencies
|
|
138
|
-
and library_data.metadata.dependencies.pip_dependencies
|
|
139
|
-
):
|
|
140
|
-
return InstallationResult(
|
|
141
|
-
installation_path=self.file_path,
|
|
142
|
-
venv_path="",
|
|
143
|
-
issues=problems,
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
pip_install_flags = library_data.metadata.dependencies.pip_install_flags
|
|
147
|
-
if pip_install_flags is None:
|
|
148
|
-
pip_install_flags = []
|
|
149
|
-
pip_dependencies = library_data.metadata.dependencies.pip_dependencies
|
|
150
|
-
|
|
151
|
-
# Determine venv path for dependency installation
|
|
152
|
-
venv_path = library_manager._get_library_venv_path(library_data.name, self.file_path)
|
|
153
|
-
|
|
154
|
-
# Only install dependencies if conditions are met
|
|
155
|
-
library_venv_python_path = None
|
|
156
|
-
try:
|
|
157
|
-
library_venv_python_path = await library_manager._init_library_venv(venv_path)
|
|
158
|
-
except RuntimeError as e:
|
|
159
|
-
problems.append(
|
|
160
|
-
LifecycleIssue(
|
|
161
|
-
message=str(e),
|
|
162
|
-
severity=LibraryStatus.UNUSABLE,
|
|
163
|
-
)
|
|
164
|
-
)
|
|
165
|
-
# Return early for blocking issues
|
|
166
|
-
return InstallationResult(
|
|
167
|
-
installation_path=self.file_path,
|
|
168
|
-
venv_path=str(venv_path) if venv_path else "",
|
|
169
|
-
issues=problems,
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
if library_venv_python_path and library_manager._can_write_to_venv_location(library_venv_python_path):
|
|
173
|
-
# Check disk space before installing dependencies
|
|
174
|
-
config_manager = GriptapeNodes.ConfigManager()
|
|
175
|
-
min_space_gb = config_manager.get_config_value("minimum_disk_space_gb_libraries")
|
|
176
|
-
if not OSManager.check_available_disk_space(Path(venv_path), min_space_gb):
|
|
177
|
-
error_msg = OSManager.format_disk_space_error(Path(venv_path))
|
|
178
|
-
problems.append(
|
|
179
|
-
LifecycleIssue(
|
|
180
|
-
message=f"Insufficient disk space for dependencies (requires {min_space_gb} GB): {error_msg}",
|
|
181
|
-
severity=LibraryStatus.UNUSABLE,
|
|
182
|
-
)
|
|
183
|
-
)
|
|
184
|
-
# Return early for blocking issues
|
|
185
|
-
return InstallationResult(
|
|
186
|
-
installation_path=self.file_path,
|
|
187
|
-
venv_path=str(venv_path) if venv_path else "",
|
|
188
|
-
issues=problems,
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
# Grab the python executable from the virtual environment so that we can pip install there
|
|
192
|
-
logger.info("Installing dependencies for library '%s' with pip in venv at %s", library_data.name, venv_path)
|
|
193
|
-
try:
|
|
194
|
-
await subprocess_run(
|
|
195
|
-
[
|
|
196
|
-
sys.executable,
|
|
197
|
-
"-m",
|
|
198
|
-
"uv",
|
|
199
|
-
"pip",
|
|
200
|
-
"install",
|
|
201
|
-
*pip_dependencies,
|
|
202
|
-
*pip_install_flags,
|
|
203
|
-
"--python",
|
|
204
|
-
str(library_venv_python_path),
|
|
205
|
-
],
|
|
206
|
-
check=True,
|
|
207
|
-
capture_output=True,
|
|
208
|
-
text=True,
|
|
209
|
-
)
|
|
210
|
-
except subprocess.CalledProcessError as e:
|
|
211
|
-
error_details = f"return code={e.returncode}, stdout={e.stdout}, stderr={e.stderr}"
|
|
212
|
-
problems.append(
|
|
213
|
-
LifecycleIssue(
|
|
214
|
-
message=f"Dependency installation failed: {error_details}",
|
|
215
|
-
severity=LibraryStatus.FLAWED,
|
|
216
|
-
)
|
|
217
|
-
)
|
|
218
|
-
elif library_venv_python_path:
|
|
219
|
-
logger.debug(
|
|
220
|
-
"Skipping dependency installation for library '%s' - venv location at %s is not writable",
|
|
221
|
-
library_data.name,
|
|
222
|
-
venv_path,
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
return InstallationResult(
|
|
226
|
-
installation_path=self.file_path,
|
|
227
|
-
venv_path=str(venv_path) if venv_path else "",
|
|
228
|
-
issues=problems,
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
def load_library(self, context: LibraryLifecycleContext) -> LibraryLoadedResult: # noqa: C901
|
|
232
|
-
"""Load this local file library into the registry."""
|
|
233
|
-
issues = []
|
|
234
|
-
|
|
235
|
-
# Get the LibraryManager instance to use its methods
|
|
236
|
-
library_manager = GriptapeNodes.LibraryManager()
|
|
237
|
-
|
|
238
|
-
# Get library schema from context (guaranteed to be valid at this point)
|
|
239
|
-
assert context.inspection_result is not None # noqa: S101
|
|
240
|
-
library_data = context.inspection_result.schema
|
|
241
|
-
assert library_data is not None # noqa: S101
|
|
242
|
-
|
|
243
|
-
# Use the file path from this provenance
|
|
244
|
-
file_path = self.file_path
|
|
245
|
-
base_dir = Path(file_path).parent
|
|
246
|
-
|
|
247
|
-
# Load advanced library module if specified
|
|
248
|
-
advanced_library_instance = None
|
|
249
|
-
if library_data.advanced_library_path:
|
|
250
|
-
try:
|
|
251
|
-
advanced_library_instance = library_manager._load_advanced_library_module(
|
|
252
|
-
library_data=library_data,
|
|
253
|
-
base_dir=base_dir,
|
|
254
|
-
)
|
|
255
|
-
except Exception as err:
|
|
256
|
-
issues.append(
|
|
257
|
-
LifecycleIssue(
|
|
258
|
-
message=f"Failed to load Advanced Library module from '{library_data.advanced_library_path}': {err}",
|
|
259
|
-
severity=LibraryStatus.UNUSABLE,
|
|
260
|
-
)
|
|
261
|
-
)
|
|
262
|
-
return LibraryLoadedResult(issues=issues)
|
|
263
|
-
|
|
264
|
-
# Create or get the library
|
|
265
|
-
library = None
|
|
266
|
-
try:
|
|
267
|
-
# Try to create a new library
|
|
268
|
-
library = LibraryRegistry.generate_new_library(
|
|
269
|
-
library_data=library_data,
|
|
270
|
-
mark_as_default_library=False, # TODO(#1234): determine if this should be configurable
|
|
271
|
-
advanced_library=advanced_library_instance,
|
|
272
|
-
)
|
|
273
|
-
except KeyError:
|
|
274
|
-
# Library already exists
|
|
275
|
-
issues.append(
|
|
276
|
-
LifecycleIssue(
|
|
277
|
-
message="Failed because a library with this name was already registered. Check the Settings to ensure duplicate libraries are not being loaded.",
|
|
278
|
-
severity=LibraryStatus.UNUSABLE,
|
|
279
|
-
)
|
|
280
|
-
)
|
|
281
|
-
return LibraryLoadedResult(issues=issues)
|
|
282
|
-
|
|
283
|
-
# Handle library settings
|
|
284
|
-
if library_data.settings is not None:
|
|
285
|
-
# Assign them into the config space
|
|
286
|
-
for library_data_setting in library_data.settings:
|
|
287
|
-
# Does the category exist?
|
|
288
|
-
get_category_request = GetConfigCategoryRequest(category=library_data_setting.category)
|
|
289
|
-
get_category_result = GriptapeNodes.handle_request(get_category_request)
|
|
290
|
-
if not isinstance(get_category_result, GetConfigCategoryResultSuccess):
|
|
291
|
-
# That's OK, we'll invent it. Or at least we'll try.
|
|
292
|
-
create_new_category_request = SetConfigCategoryRequest(
|
|
293
|
-
category=library_data_setting.category, contents=library_data_setting.contents
|
|
294
|
-
)
|
|
295
|
-
create_new_category_result = GriptapeNodes.handle_request(create_new_category_request)
|
|
296
|
-
if not isinstance(create_new_category_result, SetConfigCategoryResultSuccess):
|
|
297
|
-
issues.append(
|
|
298
|
-
LifecycleIssue(
|
|
299
|
-
message=f"Failed to create new config category '{library_data_setting.category}'.",
|
|
300
|
-
severity=LibraryStatus.FLAWED,
|
|
301
|
-
)
|
|
302
|
-
)
|
|
303
|
-
continue # SKIP IT
|
|
304
|
-
else:
|
|
305
|
-
# We had an existing category. Union our changes into it (not replacing anything that matched).
|
|
306
|
-
existing_category_contents = get_category_result.contents
|
|
307
|
-
existing_category_contents.update(library_data_setting.contents)
|
|
308
|
-
set_category_request = SetConfigCategoryRequest(
|
|
309
|
-
category=library_data_setting.category, contents=existing_category_contents
|
|
310
|
-
)
|
|
311
|
-
set_category_result = GriptapeNodes.handle_request(set_category_request)
|
|
312
|
-
if not isinstance(set_category_result, SetConfigCategoryResultSuccess):
|
|
313
|
-
issues.append(
|
|
314
|
-
LifecycleIssue(
|
|
315
|
-
message=f"Failed to update config category '{library_data_setting.category}'.",
|
|
316
|
-
severity=LibraryStatus.FLAWED,
|
|
317
|
-
)
|
|
318
|
-
)
|
|
319
|
-
continue # SKIP IT
|
|
320
|
-
|
|
321
|
-
# Get library version from schema metadata
|
|
322
|
-
library_version = library_data.metadata.library_version
|
|
323
|
-
|
|
324
|
-
# Add the directory to the Python path to allow for relative imports
|
|
325
|
-
sys.path.insert(0, str(base_dir))
|
|
326
|
-
|
|
327
|
-
# Attempt to load nodes from the library
|
|
328
|
-
library_load_results = library_manager._attempt_load_nodes_from_library(
|
|
329
|
-
library_data=library_data,
|
|
330
|
-
library=library,
|
|
331
|
-
base_dir=base_dir,
|
|
332
|
-
library_file_path=file_path,
|
|
333
|
-
library_version=library_version,
|
|
334
|
-
problems=[], # We'll handle problems through issues instead
|
|
335
|
-
)
|
|
336
|
-
|
|
337
|
-
# Convert any problems from library_load_results to issues
|
|
338
|
-
if library_load_results.problems:
|
|
339
|
-
# Group problems by type and collate them for display
|
|
340
|
-
problems_by_type = defaultdict(list)
|
|
341
|
-
for problem in library_load_results.problems:
|
|
342
|
-
problems_by_type[type(problem)].append(problem)
|
|
343
|
-
|
|
344
|
-
# Collate each group
|
|
345
|
-
collated_strings = []
|
|
346
|
-
for problem_class, instances in problems_by_type.items():
|
|
347
|
-
collated_display = problem_class.collate_problems_for_display(instances)
|
|
348
|
-
collated_strings.append(collated_display)
|
|
349
|
-
|
|
350
|
-
collated_problems = "\n".join(collated_strings)
|
|
351
|
-
issues.append(
|
|
352
|
-
LifecycleIssue(
|
|
353
|
-
message=collated_problems,
|
|
354
|
-
severity=library_load_results.status,
|
|
355
|
-
)
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
return LibraryLoadedResult(issues=issues)
|
|
359
|
-
|
|
360
|
-
def _validate_file_exists(self) -> bool:
|
|
361
|
-
"""Validate that the library file exists and is readable."""
|
|
362
|
-
try:
|
|
363
|
-
path = Path(self.file_path)
|
|
364
|
-
return path.exists() and path.is_file() and os.access(path, os.R_OK)
|
|
365
|
-
except Exception as e:
|
|
366
|
-
logger.error("Failed to validate file %s: %s", self.file_path, e)
|
|
367
|
-
return False
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
"""Package library provenance implementation."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from dataclasses import dataclass
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import TYPE_CHECKING
|
|
8
|
-
|
|
9
|
-
from xdg_base_dirs import xdg_data_home
|
|
10
|
-
|
|
11
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.data_models import (
|
|
12
|
-
EvaluationResult,
|
|
13
|
-
InspectionResult,
|
|
14
|
-
InstallationResult,
|
|
15
|
-
LibraryLoadedResult,
|
|
16
|
-
LifecycleIssue,
|
|
17
|
-
)
|
|
18
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.base import LibraryProvenance
|
|
19
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_status import LibraryStatus
|
|
20
|
-
|
|
21
|
-
if TYPE_CHECKING:
|
|
22
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_fsm import LibraryLifecycleContext
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@dataclass(frozen=True)
|
|
26
|
-
class LibraryProvenancePackage(LibraryProvenance):
|
|
27
|
-
"""Reference to a package library."""
|
|
28
|
-
|
|
29
|
-
requirement_specifier: str
|
|
30
|
-
|
|
31
|
-
def get_display_name(self) -> str:
|
|
32
|
-
"""Get a human-readable name for this provenance."""
|
|
33
|
-
return f"Package: {self.requirement_specifier}"
|
|
34
|
-
|
|
35
|
-
def inspect(self) -> InspectionResult:
|
|
36
|
-
"""Inspect this package to extract schema and identify issues."""
|
|
37
|
-
# TODO: Implement package inspection (https://github.com/griptape-ai/griptape-nodes/issues/1234)
|
|
38
|
-
# This should:
|
|
39
|
-
# 1. Check if package is available in PyPI or other repositories
|
|
40
|
-
# 2. Download and inspect package metadata
|
|
41
|
-
# 3. Extract library schema from package
|
|
42
|
-
|
|
43
|
-
return InspectionResult(
|
|
44
|
-
schema=None,
|
|
45
|
-
issues=[
|
|
46
|
-
LifecycleIssue(
|
|
47
|
-
message=f"Package inspection not yet implemented for {self.requirement_specifier}",
|
|
48
|
-
severity=LibraryStatus.UNUSABLE,
|
|
49
|
-
)
|
|
50
|
-
],
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
def evaluate(self, context: LibraryLifecycleContext) -> EvaluationResult: # noqa: ARG002
|
|
54
|
-
"""Evaluate this package for conflicts/issues."""
|
|
55
|
-
issues = []
|
|
56
|
-
issues.append(
|
|
57
|
-
LifecycleIssue(
|
|
58
|
-
message="Package evaluation not yet implemented",
|
|
59
|
-
severity=LibraryStatus.UNUSABLE,
|
|
60
|
-
)
|
|
61
|
-
)
|
|
62
|
-
return EvaluationResult(issues=issues)
|
|
63
|
-
|
|
64
|
-
async def install(self, context: LibraryLifecycleContext) -> InstallationResult: # noqa: ARG002
|
|
65
|
-
"""Install this package library."""
|
|
66
|
-
issues = []
|
|
67
|
-
issues.append(
|
|
68
|
-
LifecycleIssue(
|
|
69
|
-
message="Package installation not yet implemented",
|
|
70
|
-
severity=LibraryStatus.UNUSABLE,
|
|
71
|
-
)
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
# TODO: Implement package installation (https://github.com/griptape-ai/griptape-nodes/issues/1234)
|
|
75
|
-
# This should:
|
|
76
|
-
# 1. Create virtual environment
|
|
77
|
-
# 2. Install package using pip
|
|
78
|
-
# 3. Extract library files from installed package
|
|
79
|
-
|
|
80
|
-
return InstallationResult(
|
|
81
|
-
installation_path="",
|
|
82
|
-
venv_path="",
|
|
83
|
-
issues=issues,
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
def load_library(self, context: LibraryLifecycleContext) -> LibraryLoadedResult: # noqa: ARG002
|
|
87
|
-
"""Load this package library into the registry."""
|
|
88
|
-
issues = []
|
|
89
|
-
issues.append(
|
|
90
|
-
LifecycleIssue(
|
|
91
|
-
message="Package loading not yet implemented",
|
|
92
|
-
severity=LibraryStatus.UNUSABLE,
|
|
93
|
-
)
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
return LibraryLoadedResult(issues=issues)
|
|
97
|
-
|
|
98
|
-
def _get_base_venv_directory(self) -> str:
|
|
99
|
-
"""Get the base directory for virtual environments."""
|
|
100
|
-
return str(xdg_data_home() / "griptape_nodes" / "library_venvs")
|
|
101
|
-
|
|
102
|
-
def _ensure_venv_directory_exists(self, venv_dir: str) -> None:
|
|
103
|
-
"""Ensure the virtual environment directory exists."""
|
|
104
|
-
Path(venv_dir).mkdir(parents=True, exist_ok=True)
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
"""Sandbox library provenance implementation."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import logging
|
|
6
|
-
import os
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
from typing import TYPE_CHECKING
|
|
10
|
-
|
|
11
|
-
from pydantic import BaseModel, Field
|
|
12
|
-
|
|
13
|
-
from griptape_nodes.node_library.library_registry import LibraryMetadata, LibrarySchema
|
|
14
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.data_models import (
|
|
15
|
-
EvaluationResult,
|
|
16
|
-
InspectionResult,
|
|
17
|
-
InstallationResult,
|
|
18
|
-
LibraryLoadedResult,
|
|
19
|
-
LifecycleIssue,
|
|
20
|
-
)
|
|
21
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.base import LibraryProvenance
|
|
22
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_status import LibraryStatus
|
|
23
|
-
|
|
24
|
-
if TYPE_CHECKING:
|
|
25
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_fsm import LibraryLifecycleContext
|
|
26
|
-
|
|
27
|
-
logger = logging.getLogger("griptape_nodes")
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class LibraryPreferenceSandbox(BaseModel):
|
|
31
|
-
"""Serializable preference for a sandbox library directory."""
|
|
32
|
-
|
|
33
|
-
directory_path: str = Field(description="Path to the sandbox library directory")
|
|
34
|
-
active: bool = Field(default=True, description="Whether this sandbox library is active")
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@dataclass(frozen=True)
|
|
38
|
-
class LibraryProvenanceSandbox(LibraryProvenance):
|
|
39
|
-
"""Reference to a sandbox library (dynamically assembled from node files)."""
|
|
40
|
-
|
|
41
|
-
sandbox_path: str
|
|
42
|
-
|
|
43
|
-
def get_display_name(self) -> str:
|
|
44
|
-
"""Get a human-readable name for this provenance."""
|
|
45
|
-
return f"Sandbox: {self.sandbox_path}"
|
|
46
|
-
|
|
47
|
-
def inspect(self) -> InspectionResult:
|
|
48
|
-
"""Inspect this sandbox to dynamically create schema from node files."""
|
|
49
|
-
if not self._validate_sandbox_path():
|
|
50
|
-
return InspectionResult(
|
|
51
|
-
schema=None,
|
|
52
|
-
issues=[
|
|
53
|
-
LifecycleIssue(
|
|
54
|
-
message=f"Sandbox directory does not exist or is not readable: {self.sandbox_path}",
|
|
55
|
-
severity=LibraryStatus.UNUSABLE,
|
|
56
|
-
)
|
|
57
|
-
],
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
# TODO: Implement dynamic library schema creation from node files (https://github.com/griptape-ai/griptape-nodes/issues/1234)
|
|
61
|
-
# This should:
|
|
62
|
-
# 1. Scan the sandbox directory for Python files
|
|
63
|
-
# 2. Extract node class definitions and metadata
|
|
64
|
-
# 3. Dynamically create LibrarySchema with discovered nodes
|
|
65
|
-
# 4. Generate appropriate categories and metadata
|
|
66
|
-
|
|
67
|
-
# For now, return a basic schema structure
|
|
68
|
-
# This is a placeholder that should be replaced with actual node discovery
|
|
69
|
-
sandbox_name = Path(self.sandbox_path).name
|
|
70
|
-
|
|
71
|
-
# Create minimal metadata for sandbox
|
|
72
|
-
metadata = LibraryMetadata(
|
|
73
|
-
author="Sandbox Developer",
|
|
74
|
-
description=f"Dynamically discovered sandbox library from {sandbox_name}",
|
|
75
|
-
library_version="dev",
|
|
76
|
-
engine_version="1.0.0",
|
|
77
|
-
tags=["sandbox", "development"],
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
# Create basic schema - this should be replaced with actual node discovery
|
|
81
|
-
schema = LibrarySchema(
|
|
82
|
-
name=sandbox_name,
|
|
83
|
-
library_schema_version="1.0.0",
|
|
84
|
-
metadata=metadata,
|
|
85
|
-
categories=[], # Should be populated from discovered nodes
|
|
86
|
-
nodes=[], # Should be populated from discovered nodes
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
return InspectionResult(schema=schema, issues=[])
|
|
90
|
-
|
|
91
|
-
def evaluate(self, context: LibraryLifecycleContext) -> EvaluationResult: # noqa: ARG002
|
|
92
|
-
"""Evaluate this sandbox for conflicts/issues."""
|
|
93
|
-
issues = []
|
|
94
|
-
|
|
95
|
-
# Check if sandbox is still accessible
|
|
96
|
-
if not self._validate_sandbox_path():
|
|
97
|
-
issues.append(
|
|
98
|
-
LifecycleIssue(
|
|
99
|
-
message=f"Sandbox directory is no longer accessible: {self.sandbox_path}",
|
|
100
|
-
severity=LibraryStatus.UNUSABLE,
|
|
101
|
-
)
|
|
102
|
-
)
|
|
103
|
-
return EvaluationResult(issues=issues)
|
|
104
|
-
|
|
105
|
-
# TODO: Add sandbox-specific evaluation logic (https://github.com/griptape-ai/griptape-nodes/issues/1234)
|
|
106
|
-
# This could include:
|
|
107
|
-
# - Checking for naming conflicts with existing libraries
|
|
108
|
-
# - Validating node implementations
|
|
109
|
-
# - Checking for missing dependencies
|
|
110
|
-
|
|
111
|
-
return EvaluationResult(issues=issues)
|
|
112
|
-
|
|
113
|
-
async def install(self, context: LibraryLifecycleContext) -> InstallationResult: # noqa: ARG002
|
|
114
|
-
"""Install this sandbox library."""
|
|
115
|
-
issues = []
|
|
116
|
-
|
|
117
|
-
# Sandbox libraries don't need complex installation
|
|
118
|
-
# They're loaded directly from the sandbox directory
|
|
119
|
-
return InstallationResult(
|
|
120
|
-
installation_path=self.sandbox_path,
|
|
121
|
-
venv_path="",
|
|
122
|
-
issues=issues,
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
def load_library(self, context: LibraryLifecycleContext) -> LibraryLoadedResult:
|
|
126
|
-
"""Load this sandbox library into the registry."""
|
|
127
|
-
issues = []
|
|
128
|
-
|
|
129
|
-
# Get library schema from context
|
|
130
|
-
library_schema = context.inspection_result.schema if context.inspection_result else None
|
|
131
|
-
|
|
132
|
-
if not library_schema or not library_schema.metadata:
|
|
133
|
-
issues.append(
|
|
134
|
-
LifecycleIssue(
|
|
135
|
-
message="No metadata available for loading",
|
|
136
|
-
severity=LibraryStatus.FLAWED,
|
|
137
|
-
)
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
# TODO: Actually register the sandbox library with the LibraryRegistry (https://github.com/griptape-ai/griptape-nodes/issues/1234)
|
|
141
|
-
# This would involve:
|
|
142
|
-
# 1. Creating a Library instance from the dynamically discovered nodes
|
|
143
|
-
# 2. Adding it to the LibraryRegistry
|
|
144
|
-
# 3. Handling any registration conflicts or errors
|
|
145
|
-
|
|
146
|
-
return LibraryLoadedResult(issues=issues)
|
|
147
|
-
|
|
148
|
-
def _validate_sandbox_path(self) -> bool:
|
|
149
|
-
"""Validate that the sandbox path exists and is readable."""
|
|
150
|
-
try:
|
|
151
|
-
path = Path(self.sandbox_path)
|
|
152
|
-
return path.exists() and path.is_dir() and os.access(path, os.R_OK)
|
|
153
|
-
except Exception as e:
|
|
154
|
-
logger.error("Failed to validate sandbox path %s: %s", self.sandbox_path, e)
|
|
155
|
-
return False
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"""Library provenance classes for tracking library sources."""
|
|
2
|
-
|
|
3
|
-
# Re-export all provenance classes from their new location
|
|
4
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.base import LibraryProvenance
|
|
5
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.github import LibraryProvenanceGitHub
|
|
6
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.local_file import (
|
|
7
|
-
LibraryProvenanceLocalFile,
|
|
8
|
-
)
|
|
9
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.package import LibraryProvenancePackage
|
|
10
|
-
from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.sandbox import LibraryProvenanceSandbox
|
|
11
|
-
|
|
12
|
-
__all__ = [
|
|
13
|
-
"LibraryProvenance",
|
|
14
|
-
"LibraryProvenanceGitHub",
|
|
15
|
-
"LibraryProvenanceLocalFile",
|
|
16
|
-
"LibraryProvenancePackage",
|
|
17
|
-
"LibraryProvenanceSandbox",
|
|
18
|
-
]
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"""Library status enumeration."""
|
|
2
|
-
|
|
3
|
-
from enum import StrEnum
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class LibraryStatus(StrEnum):
|
|
7
|
-
"""Status of the library that was attempted to be loaded."""
|
|
8
|
-
|
|
9
|
-
GOOD = "GOOD" # No errors detected during loading. Registered.
|
|
10
|
-
FLAWED = "FLAWED" # Some errors detected, but recoverable. Registered.
|
|
11
|
-
UNUSABLE = "UNUSABLE" # Errors detected and not recoverable. Not registered.
|
|
12
|
-
MISSING = "MISSING" # File not found. Not registered.
|
|
File without changes
|
|
File without changes
|