griptape-nodes 0.65.6__py3-none-any.whl → 0.66.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. griptape_nodes/common/node_executor.py +352 -27
  2. griptape_nodes/drivers/storage/base_storage_driver.py +12 -3
  3. griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +18 -2
  4. griptape_nodes/drivers/storage/local_storage_driver.py +42 -5
  5. griptape_nodes/exe_types/base_iterative_nodes.py +0 -1
  6. griptape_nodes/exe_types/connections.py +42 -0
  7. griptape_nodes/exe_types/core_types.py +2 -2
  8. griptape_nodes/exe_types/node_groups/__init__.py +2 -1
  9. griptape_nodes/exe_types/node_groups/base_iterative_node_group.py +177 -0
  10. griptape_nodes/exe_types/node_groups/base_node_group.py +1 -0
  11. griptape_nodes/exe_types/node_groups/subflow_node_group.py +35 -2
  12. griptape_nodes/exe_types/param_types/parameter_audio.py +1 -1
  13. griptape_nodes/exe_types/param_types/parameter_bool.py +1 -1
  14. griptape_nodes/exe_types/param_types/parameter_button.py +1 -1
  15. griptape_nodes/exe_types/param_types/parameter_float.py +1 -1
  16. griptape_nodes/exe_types/param_types/parameter_image.py +1 -1
  17. griptape_nodes/exe_types/param_types/parameter_int.py +1 -1
  18. griptape_nodes/exe_types/param_types/parameter_number.py +1 -1
  19. griptape_nodes/exe_types/param_types/parameter_string.py +1 -1
  20. griptape_nodes/exe_types/param_types/parameter_three_d.py +1 -1
  21. griptape_nodes/exe_types/param_types/parameter_video.py +1 -1
  22. griptape_nodes/machines/control_flow.py +5 -4
  23. griptape_nodes/machines/dag_builder.py +121 -55
  24. griptape_nodes/machines/fsm.py +10 -0
  25. griptape_nodes/machines/parallel_resolution.py +39 -38
  26. griptape_nodes/machines/sequential_resolution.py +29 -3
  27. griptape_nodes/node_library/library_registry.py +41 -2
  28. griptape_nodes/retained_mode/events/library_events.py +147 -8
  29. griptape_nodes/retained_mode/events/os_events.py +12 -4
  30. griptape_nodes/retained_mode/managers/fitness_problems/libraries/__init__.py +2 -0
  31. griptape_nodes/retained_mode/managers/fitness_problems/libraries/incompatible_requirements_problem.py +34 -0
  32. griptape_nodes/retained_mode/managers/flow_manager.py +133 -20
  33. griptape_nodes/retained_mode/managers/library_manager.py +1324 -564
  34. griptape_nodes/retained_mode/managers/node_manager.py +9 -3
  35. griptape_nodes/retained_mode/managers/os_manager.py +429 -65
  36. griptape_nodes/retained_mode/managers/resource_types/compute_resource.py +82 -0
  37. griptape_nodes/retained_mode/managers/resource_types/os_resource.py +17 -0
  38. griptape_nodes/retained_mode/managers/static_files_manager.py +21 -8
  39. griptape_nodes/retained_mode/managers/version_compatibility_manager.py +3 -3
  40. griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +5 -5
  41. griptape_nodes/version_compatibility/versions/v0_65_4/__init__.py +5 -0
  42. griptape_nodes/version_compatibility/versions/v0_65_4/run_in_parallel_to_run_in_order.py +79 -0
  43. griptape_nodes/version_compatibility/versions/v0_65_5/__init__.py +5 -0
  44. griptape_nodes/version_compatibility/versions/v0_65_5/flux_2_removed_parameters.py +85 -0
  45. {griptape_nodes-0.65.6.dist-info → griptape_nodes-0.66.1.dist-info}/METADATA +1 -1
  46. {griptape_nodes-0.65.6.dist-info → griptape_nodes-0.66.1.dist-info}/RECORD +48 -53
  47. griptape_nodes/retained_mode/managers/library_lifecycle/__init__.py +0 -45
  48. griptape_nodes/retained_mode/managers/library_lifecycle/data_models.py +0 -191
  49. griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +0 -346
  50. griptape_nodes/retained_mode/managers/library_lifecycle/library_fsm.py +0 -439
  51. griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/__init__.py +0 -17
  52. griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/base.py +0 -82
  53. griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/github.py +0 -116
  54. griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +0 -367
  55. griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/package.py +0 -104
  56. griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/sandbox.py +0 -155
  57. griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance.py +0 -18
  58. griptape_nodes/retained_mode/managers/library_lifecycle/library_status.py +0 -12
  59. {griptape_nodes-0.65.6.dist-info → griptape_nodes-0.66.1.dist-info}/WHEEL +0 -0
  60. {griptape_nodes-0.65.6.dist-info → griptape_nodes-0.66.1.dist-info}/entry_points.txt +0 -0
@@ -1,439 +0,0 @@
1
- """Library lifecycle finite state machine implementation."""
2
-
3
- from __future__ import annotations
4
-
5
- import logging
6
- from dataclasses import dataclass
7
- from typing import TYPE_CHECKING
8
-
9
- from griptape_nodes.machines.fsm import FSM, State
10
- from griptape_nodes.retained_mode.managers.library_lifecycle.data_models import (
11
- EvaluationResult,
12
- InspectionResult,
13
- InstallationResult,
14
- LibraryLoadedResult,
15
- LifecycleIssue,
16
- )
17
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_status import LibraryStatus
18
-
19
- if TYPE_CHECKING:
20
- from griptape_nodes.node_library.library_registry import LibrarySchema
21
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance import LibraryProvenance
22
-
23
- StateType = type[State]
24
-
25
- logger = logging.getLogger("griptape_nodes")
26
-
27
-
28
- class InvalidStateTransitionError(Exception):
29
- """Raised when an invalid state transition is attempted."""
30
-
31
- def __init__(self, current_state: StateType | None, requested_state: StateType, reason: str):
32
- self.current_state = current_state
33
- self.requested_state = requested_state
34
- self.reason = reason
35
- current_name = current_state.__name__ if current_state else "None"
36
- super().__init__(f"Cannot transition from {current_name} to {requested_state.__name__}: {reason}")
37
-
38
-
39
- @dataclass
40
- class LibraryLifecycleContext:
41
- """Context object for library lifecycle state machine."""
42
-
43
- # Core identity
44
- provenance: LibraryProvenance
45
-
46
- # State machine data populated as we progress
47
- inspection_result: InspectionResult | None = None
48
- evaluation_result: EvaluationResult | None = None
49
- installation_result: InstallationResult | None = None
50
- library_loaded_result: LibraryLoadedResult | None = None
51
-
52
- def get_library_schema(self) -> LibrarySchema | None:
53
- """Get the library schema from inspection result."""
54
- return self.inspection_result.schema if self.inspection_result else None
55
-
56
- def get_inspection_issues(self) -> list[LifecycleIssue]:
57
- """Get inspection issues from inspection result."""
58
- return self.inspection_result.issues if self.inspection_result else []
59
-
60
- def get_evaluation_issues(self) -> list[LifecycleIssue]:
61
- """Get evaluation issues from evaluation result."""
62
- return self.evaluation_result.issues if self.evaluation_result else []
63
-
64
- def get_installation_issues(self) -> list[LifecycleIssue]:
65
- """Get installation issues from installation result."""
66
- return self.installation_result.issues if self.installation_result else []
67
-
68
- def get_library_loaded_issues(self) -> list[LifecycleIssue]:
69
- """Get library loaded issues from library loaded result."""
70
- return self.library_loaded_result.issues if self.library_loaded_result else []
71
-
72
- def get_effective_active_state(self) -> bool:
73
- """Get the effective active state for this library."""
74
- # TODO: Implement proper integration with LibraryPreferences from data_models (https://github.com/griptape-ai/griptape-nodes/issues/1234)
75
- # For now, return True as a fallback until the proper integration is implemented
76
- # This method should:
77
- # 1. Get the runtime library preferences (not the settings preferences)
78
- # 2. Check if library is active by name or provenance
79
- # 3. Return appropriate active state
80
- return True
81
-
82
-
83
- # States for the Library Lifecycle FSM
84
-
85
-
86
- class CandidateState(State):
87
- """Initial state where we have a library candidate ready for processing."""
88
-
89
- @staticmethod
90
- async def on_enter(context: LibraryLifecycleContext) -> StateType | None:
91
- logger.info("Library %s is now a candidate for processing", context.provenance.get_display_name())
92
- return None # Wait for explicit transition to InspectingState
93
-
94
- @staticmethod
95
- def get_allowed_transitions_for_context(context: LibraryLifecycleContext) -> set[StateType]: # noqa: ARG004
96
- """Get context-specific allowed transitions."""
97
- return {InspectingState}
98
-
99
-
100
- class InspectingState(State):
101
- """State where we inspect the library to gather metadata."""
102
-
103
- @staticmethod
104
- def get_allowed_transitions_for_context(context: LibraryLifecycleContext) -> set[StateType]: # noqa: ARG004
105
- """Get context-specific allowed transitions."""
106
- return {InspectedState}
107
-
108
- @staticmethod
109
- async def on_enter(context: LibraryLifecycleContext) -> StateType | None:
110
- logger.info("Inspecting library %s", context.provenance.get_display_name())
111
-
112
- # Store inspection result directly
113
- context.inspection_result = context.provenance.inspect()
114
-
115
- if context.inspection_result.schema:
116
- # Library name is now accessible through the schema
117
- library_name = context.inspection_result.schema.name
118
- logger.info("Successfully loaded metadata for library %s", library_name)
119
- else:
120
- logger.warning("Failed to load metadata for library %s", context.provenance.get_display_name())
121
-
122
- # Check if inspection result is disqualifying
123
- if not context.inspection_result.is_usable():
124
- logger.error(
125
- "Library %s inspection failed with disqualifying issues: %s",
126
- context.provenance.get_display_name(),
127
- [issue.message for issue in context.inspection_result.issues],
128
- )
129
- # For disqualifying results, we still transition to InspectedState but it will have no allowed transitions
130
- return InspectedState
131
-
132
- # Auto-transition to InspectedState
133
- return InspectedState
134
-
135
-
136
- class InspectedState(State):
137
- """State where inspection is complete and we have metadata."""
138
-
139
- @staticmethod
140
- def get_allowed_transitions_for_context(context: LibraryLifecycleContext) -> set[StateType]:
141
- """Get context-specific allowed transitions."""
142
- # If inspection result is unusable, block all transitions
143
- if context.inspection_result and not context.inspection_result.is_usable():
144
- return set()
145
- return {EvaluatingState}
146
-
147
- @staticmethod
148
- async def on_enter(context: LibraryLifecycleContext) -> StateType | None:
149
- if context.inspection_result and context.inspection_result.issues:
150
- logger.warning(
151
- "Library %s inspection completed with problems: %s",
152
- context.provenance.get_display_name(),
153
- [issue.message for issue in context.inspection_result.issues],
154
- )
155
- else:
156
- logger.info("Library %s inspection completed successfully", context.provenance.get_display_name())
157
-
158
- return None # Wait for explicit transition to EvaluatingState
159
-
160
-
161
- class EvaluatingState(State):
162
- """State where we evaluate the library against current system state."""
163
-
164
- @staticmethod
165
- def get_allowed_transitions_for_context(context: LibraryLifecycleContext) -> set[StateType]: # noqa: ARG004
166
- """Get context-specific allowed transitions."""
167
- return {EvaluatedState}
168
-
169
- @staticmethod
170
- async def on_enter(context: LibraryLifecycleContext) -> StateType | None:
171
- logger.info("Evaluating library %s", context.provenance.get_display_name())
172
-
173
- context.evaluation_result = context.provenance.evaluate(context)
174
-
175
- # Auto-transition to EvaluatedState
176
- return EvaluatedState
177
-
178
-
179
- class EvaluatedState(State):
180
- """State where evaluation is complete."""
181
-
182
- @staticmethod
183
- def get_allowed_transitions_for_context(context: LibraryLifecycleContext) -> set[StateType]: # noqa: ARG004
184
- """Get context-specific allowed transitions."""
185
- return {InstallingState}
186
-
187
- @staticmethod
188
- async def on_enter(context: LibraryLifecycleContext) -> StateType | None:
189
- evaluation_issues = context.get_evaluation_issues()
190
- if evaluation_issues:
191
- logger.warning(
192
- "Library %s evaluation completed with problems: %s",
193
- context.provenance.get_display_name(),
194
- [issue.message for issue in evaluation_issues],
195
- )
196
- else:
197
- logger.info("Library %s evaluation completed successfully", context.provenance.get_display_name())
198
-
199
- return None # Wait for explicit transition to InstallingState
200
-
201
-
202
- class InstallingState(State):
203
- """State where we install the library and its dependencies."""
204
-
205
- @staticmethod
206
- def get_allowed_transitions_for_context(context: LibraryLifecycleContext) -> set[StateType]: # noqa: ARG004
207
- """Get context-specific allowed transitions."""
208
- return {InstalledState}
209
-
210
- @staticmethod
211
- async def on_enter(context: LibraryLifecycleContext) -> StateType | None:
212
- logger.info("Installing library %s", context.provenance.get_display_name())
213
-
214
- # Check if user has disabled this library
215
- if not context.get_effective_active_state():
216
- issues = [LifecycleIssue(message="Library disabled by user", severity=LibraryStatus.FLAWED)]
217
- context.installation_result = InstallationResult(installation_path="", venv_path="", issues=issues)
218
- logger.info("Library %s installation skipped - disabled by user", context.provenance.get_display_name())
219
- return InstalledState
220
-
221
- # Perform installation using delegation
222
- context.installation_result = await context.provenance.install(context)
223
-
224
- # Auto-transition to InstalledState
225
- return InstalledState
226
-
227
-
228
- class InstalledState(State):
229
- """State where installation is complete."""
230
-
231
- @staticmethod
232
- def get_allowed_transitions_for_context(context: LibraryLifecycleContext) -> set[StateType]: # noqa: ARG004
233
- """Get context-specific allowed transitions."""
234
- return {LoadingState}
235
-
236
- @staticmethod
237
- async def on_enter(context: LibraryLifecycleContext) -> StateType | None:
238
- installation_issues = context.get_installation_issues()
239
- if installation_issues:
240
- logger.warning(
241
- "Library %s installation completed with problems: %s",
242
- context.provenance.get_display_name(),
243
- [issue.message for issue in installation_issues],
244
- )
245
- else:
246
- logger.info("Library %s installation completed successfully", context.provenance.get_display_name())
247
-
248
- return None # Wait for explicit transition to LoadingState
249
-
250
-
251
- class LoadingState(State):
252
- """State where we load the library into the registry."""
253
-
254
- @staticmethod
255
- def get_allowed_transitions_for_context(context: LibraryLifecycleContext) -> set[StateType]: # noqa: ARG004
256
- """Get context-specific allowed transitions."""
257
- return {LoadedState}
258
-
259
- @staticmethod
260
- async def on_enter(context: LibraryLifecycleContext) -> StateType | None:
261
- logger.info("Loading library %s", context.provenance.get_display_name())
262
-
263
- # Check if user has disabled this library
264
- if not context.get_effective_active_state():
265
- issues = [LifecycleIssue(message="Library disabled by user", severity=LibraryStatus.FLAWED)]
266
- context.library_loaded_result = LibraryLoadedResult(issues=issues)
267
- logger.info("Library %s loading skipped - disabled by user", context.provenance.get_display_name())
268
- return LoadedState
269
-
270
- # Load the library into the registry using delegation
271
- schema = context.get_library_schema()
272
- if schema is None:
273
- issues = [LifecycleIssue(message="No schema available for loading", severity=LibraryStatus.UNUSABLE)]
274
- context.library_loaded_result = LibraryLoadedResult(issues=issues)
275
- logger.error("Cannot load library %s - no schema available", context.provenance.get_display_name())
276
- return LoadedState
277
-
278
- context.library_loaded_result = context.provenance.load_library(context)
279
-
280
- logger.info("Successfully loaded library %s", context.provenance.get_display_name())
281
-
282
- # Auto-transition to LoadedState
283
- return LoadedState
284
-
285
-
286
- class LoadedState(State):
287
- """Final state where the library is loaded and ready for use."""
288
-
289
- @staticmethod
290
- def get_allowed_transitions_for_context(context: LibraryLifecycleContext) -> set[StateType]: # noqa: ARG004
291
- """Get context-specific allowed transitions."""
292
- return set() # Terminal state
293
-
294
- @staticmethod
295
- async def on_enter(context: LibraryLifecycleContext) -> StateType | None:
296
- library_loaded_issues = context.get_library_loaded_issues()
297
- if library_loaded_issues:
298
- logger.warning(
299
- "Library %s loading completed with problems: %s",
300
- context.provenance.get_display_name(),
301
- [issue.message for issue in library_loaded_issues],
302
- )
303
- else:
304
- logger.info("Library %s is now loaded and ready for use", context.provenance.get_display_name())
305
-
306
- return None # Terminal state
307
-
308
-
309
- class LibraryLifecycleFSM(FSM[LibraryLifecycleContext]):
310
- """Finite state machine for managing library lifecycle."""
311
-
312
- def __init__(self, provenance: LibraryProvenance) -> None:
313
- context = LibraryLifecycleContext(provenance=provenance)
314
- super().__init__(context)
315
-
316
- async def start_lifecycle(self) -> None:
317
- """Start the library lifecycle from CandidateState."""
318
- if self._current_state is not None:
319
- raise InvalidStateTransitionError(self._current_state, CandidateState, "Lifecycle has already been started")
320
- await self.start(CandidateState)
321
-
322
- async def begin_inspection(self) -> None:
323
- """Explicitly transition from Candidate to Inspecting."""
324
- self._validate_state_transition(InspectingState)
325
- await self.transition_state(InspectingState)
326
-
327
- async def begin_evaluation(self) -> None:
328
- """Explicitly transition from Inspected to Evaluating."""
329
- self._validate_state_transition(EvaluatingState)
330
- await self.transition_state(EvaluatingState)
331
-
332
- async def begin_installation(self) -> None:
333
- """Explicitly transition from Evaluated to Installing."""
334
- self._validate_state_transition(InstallingState)
335
- await self.transition_state(InstallingState)
336
-
337
- async def begin_loading(self) -> None:
338
- """Explicitly transition from Installed to Loading."""
339
- self._validate_state_transition(LoadingState)
340
- await self.transition_state(LoadingState)
341
-
342
- def get_context(self) -> LibraryLifecycleContext:
343
- """Get the current context."""
344
- return self._context
345
-
346
- def is_loaded(self) -> bool:
347
- """Check if the library is in the loaded state."""
348
- return self._current_state is LoadedState
349
-
350
- def has_problems(self) -> bool:
351
- """Check if the library has any problems."""
352
- context = self._context
353
- return bool(
354
- context.get_inspection_issues()
355
- or context.get_evaluation_issues()
356
- or context.get_installation_issues()
357
- or context.get_library_loaded_issues()
358
- )
359
-
360
- def get_all_problems(self) -> list[str]:
361
- """Get all problems from all stages."""
362
- context = self._context
363
- all_problems = []
364
- all_problems.extend([issue.message for issue in context.get_inspection_issues()])
365
- all_problems.extend([issue.message for issue in context.get_evaluation_issues()])
366
- all_problems.extend([issue.message for issue in context.get_installation_issues()])
367
- all_problems.extend([issue.message for issue in context.get_library_loaded_issues()])
368
- return all_problems
369
-
370
- def _validate_state_transition(self, target_state: StateType) -> None:
371
- """Validate that we can transition to the target state using state-based rules.
372
-
373
- Args:
374
- target_state: The state we want to transition to
375
- """
376
- if self._current_state is None:
377
- raise InvalidStateTransitionError(
378
- self._current_state, target_state, "No current state - lifecycle not started"
379
- )
380
-
381
- # Check if target state is allowed from current state
382
- allowed_transitions = self._current_state.get_allowed_transitions_for_context(self._context) # type: ignore[attr-defined]
383
- if target_state not in allowed_transitions:
384
- allowed_names = [state.__name__ for state in allowed_transitions]
385
- if not allowed_names:
386
- raise InvalidStateTransitionError(
387
- self._current_state,
388
- target_state,
389
- f"No transitions allowed from {self._current_state.__name__} due to disqualifying inspection issues",
390
- )
391
- raise InvalidStateTransitionError(
392
- self._current_state,
393
- target_state,
394
- f"Cannot transition from {self._current_state.__name__} to {target_state.__name__}. "
395
- f"Allowed transitions: {allowed_names}",
396
- )
397
-
398
- # Special validation for LoadingState - requires installation result
399
- installation_result = self._context.installation_result
400
- if target_state is LoadingState and not installation_result:
401
- raise InvalidStateTransitionError(
402
- self._current_state, target_state, "Installation result is required before loading"
403
- )
404
-
405
- def can_transition_to(self, target_state: StateType) -> bool:
406
- """Check if we can transition to the target state."""
407
- try:
408
- self._validate_state_transition(target_state)
409
- except InvalidStateTransitionError:
410
- return False
411
- else:
412
- return True
413
-
414
- def can_begin_inspection(self) -> bool:
415
- """Check if we can begin inspection."""
416
- return self.can_transition_to(InspectingState)
417
-
418
- def can_begin_evaluation(self) -> bool:
419
- """Check if we can begin evaluation."""
420
- return self.can_transition_to(EvaluatingState)
421
-
422
- def can_begin_installation(self) -> bool:
423
- """Check if we can begin installation."""
424
- return self.can_transition_to(InstallingState)
425
-
426
- def can_begin_loading(self) -> bool:
427
- """Check if we can begin loading."""
428
- return self.can_transition_to(LoadingState)
429
-
430
- def get_current_state_name(self) -> str:
431
- """Get the name of the current state."""
432
- return self._current_state.__name__ if self._current_state else "None"
433
-
434
- def get_allowed_transitions(self) -> set[StateType]:
435
- """Get the set of states that can be transitioned to from the current state."""
436
- if self._current_state is None:
437
- return set()
438
-
439
- return self._current_state.get_allowed_transitions_for_context(self._context) # type: ignore[attr-defined]
@@ -1,17 +0,0 @@
1
- """Library provenance implementations."""
2
-
3
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.base import LibraryProvenance
4
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.github import LibraryProvenanceGitHub
5
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.local_file import (
6
- LibraryProvenanceLocalFile,
7
- )
8
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.package import LibraryProvenancePackage
9
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.sandbox import LibraryProvenanceSandbox
10
-
11
- __all__ = [
12
- "LibraryProvenance",
13
- "LibraryProvenanceGitHub",
14
- "LibraryProvenanceLocalFile",
15
- "LibraryProvenancePackage",
16
- "LibraryProvenanceSandbox",
17
- ]
@@ -1,82 +0,0 @@
1
- """Abstract base class for library provenance."""
2
-
3
- from __future__ import annotations
4
-
5
- from abc import ABC, abstractmethod
6
- from dataclasses import dataclass
7
- from typing import TYPE_CHECKING
8
-
9
- from griptape_nodes.retained_mode.managers.library_lifecycle.data_models import (
10
- EvaluationResult,
11
- InspectionResult,
12
- InstallationResult,
13
- LibraryEntry,
14
- LibraryLoadedResult,
15
- )
16
-
17
- if TYPE_CHECKING:
18
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_fsm import LibraryLifecycleContext
19
-
20
-
21
- @dataclass(frozen=True)
22
- class LibraryProvenance(ABC):
23
- """Pure reference to a library source."""
24
-
25
- def get_display_name(self) -> str:
26
- """Get a human-readable name for this provenance."""
27
- return f"Unknown provenance: {type(self).__name__}"
28
-
29
- def create_library_entry(self, *, active: bool = True) -> LibraryEntry:
30
- """Create a library entry for this provenance."""
31
-
32
- # Create a basic library entry that includes this provenance
33
- class BasicLibraryEntry(LibraryEntry):
34
- def __init__(self, provenance: LibraryProvenance, *, active: bool = True):
35
- super().__init__(active=active)
36
- self._provenance = provenance
37
-
38
- def get_provenance(self) -> LibraryProvenance:
39
- return self._provenance
40
-
41
- return BasicLibraryEntry(self, active=active)
42
-
43
- @abstractmethod
44
- def inspect(self) -> InspectionResult:
45
- """Inspect this provenance to extract schema and identify issues.
46
-
47
- Returns:
48
- InspectionResult with schema and categorized issues
49
- """
50
-
51
- @abstractmethod
52
- def evaluate(self, context: LibraryLifecycleContext) -> EvaluationResult:
53
- """Evaluate this provenance for conflicts/issues.
54
-
55
- Args:
56
- context: Lifecycle context containing inspection results
57
-
58
- Returns:
59
- EvaluationResult with structured issues and severity levels
60
- """
61
-
62
- @abstractmethod
63
- async def install(self, context: LibraryLifecycleContext) -> InstallationResult:
64
- """Install this provenance.
65
-
66
- Args:
67
- context: Lifecycle context containing inspection results
68
-
69
- Returns:
70
- InstallationResult with structured issues and severity levels
71
- """
72
-
73
- @abstractmethod
74
- def load_library(self, context: LibraryLifecycleContext) -> LibraryLoadedResult:
75
- """Load this provenance into the registry.
76
-
77
- Args:
78
- context: Lifecycle context containing inspection results
79
-
80
- Returns:
81
- LibraryLoadedResult with structured issues and severity levels
82
- """
@@ -1,116 +0,0 @@
1
- """GitHub 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 pydantic import BaseModel, Field
10
- from xdg_base_dirs import xdg_data_home
11
-
12
- from griptape_nodes.retained_mode.managers.library_lifecycle.data_models import (
13
- EvaluationResult,
14
- InspectionResult,
15
- InstallationResult,
16
- LibraryLoadedResult,
17
- LifecycleIssue,
18
- )
19
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_provenance.base import LibraryProvenance
20
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_status import LibraryStatus
21
-
22
- if TYPE_CHECKING:
23
- from griptape_nodes.retained_mode.managers.library_lifecycle.library_fsm import LibraryLifecycleContext
24
-
25
-
26
- class LibraryPreferenceGitHub(BaseModel):
27
- """Serializable preference for a GitHub repository library."""
28
-
29
- repository_url: str = Field(description="GitHub repository URL")
30
- branch: str | None = Field(default=None, description="Branch or ref to use (defaults to main/master)")
31
- active: bool = Field(default=True, description="Whether this GitHub library is active")
32
-
33
-
34
- @dataclass(frozen=True)
35
- class LibraryProvenanceGitHub(LibraryProvenance):
36
- """Reference to a GitHub repository library."""
37
-
38
- repository_url: str
39
- ref: str | None = None
40
-
41
- def get_display_name(self) -> str:
42
- """Get a human-readable name for this provenance."""
43
- ref_part = f"@{self.ref}" if self.ref else ""
44
- return f"GitHub: {self.repository_url}{ref_part}"
45
-
46
- def inspect(self) -> InspectionResult:
47
- """Inspect this GitHub repository to extract schema and identify issues."""
48
- # TODO: Implement GitHub repository inspection (https://github.com/griptape-ai/griptape-nodes/issues/1234)
49
- # This should:
50
- # 1. Clone or fetch repository contents
51
- # 2. Look for library schema files
52
- # 3. Extract and validate library schema
53
-
54
- return InspectionResult(
55
- schema=None,
56
- issues=[
57
- LifecycleIssue(
58
- message=f"GitHub inspection not yet implemented for {self.repository_url}",
59
- severity=LibraryStatus.UNUSABLE,
60
- )
61
- ],
62
- )
63
-
64
- def evaluate(self, context: LibraryLifecycleContext) -> EvaluationResult: # noqa: ARG002
65
- """Evaluate this GitHub repository for conflicts/issues."""
66
- issues = []
67
- issues.append(
68
- LifecycleIssue(
69
- message="GitHub evaluation not yet implemented",
70
- severity=LibraryStatus.UNUSABLE,
71
- )
72
- )
73
- return EvaluationResult(issues=issues)
74
-
75
- async def install(self, context: LibraryLifecycleContext) -> InstallationResult: # noqa: ARG002
76
- """Install this GitHub repository library."""
77
- issues = []
78
- issues.append(
79
- LifecycleIssue(
80
- message="GitHub installation not yet implemented",
81
- severity=LibraryStatus.UNUSABLE,
82
- )
83
- )
84
-
85
- # TODO: Implement GitHub repository installation (https://github.com/griptape-ai/griptape-nodes/issues/1234)
86
- # This should:
87
- # 1. Clone repository to local directory
88
- # 2. Create virtual environment
89
- # 3. Install dependencies
90
- # 4. Install repository in development mode
91
-
92
- return InstallationResult(
93
- installation_path="",
94
- venv_path="",
95
- issues=issues,
96
- )
97
-
98
- def load_library(self, context: LibraryLifecycleContext) -> LibraryLoadedResult: # noqa: ARG002
99
- """Load this GitHub repository library into the registry."""
100
- issues = []
101
- issues.append(
102
- LifecycleIssue(
103
- message="GitHub loading not yet implemented",
104
- severity=LibraryStatus.UNUSABLE,
105
- )
106
- )
107
-
108
- return LibraryLoadedResult(issues=issues)
109
-
110
- def _get_base_venv_directory(self) -> str:
111
- """Get the base directory for virtual environments."""
112
- return str(xdg_data_home() / "griptape_nodes" / "library_venvs")
113
-
114
- def _ensure_venv_directory_exists(self, venv_dir: str) -> None:
115
- """Ensure the virtual environment directory exists."""
116
- Path(venv_dir).mkdir(parents=True, exist_ok=True)