griptape-nodes 0.55.1__py3-none-any.whl → 0.56.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 (35) hide show
  1. griptape_nodes/cli/commands/init.py +88 -0
  2. griptape_nodes/cli/commands/models.py +2 -0
  3. griptape_nodes/cli/shared.py +1 -0
  4. griptape_nodes/exe_types/core_types.py +104 -0
  5. griptape_nodes/exe_types/node_types.py +9 -12
  6. griptape_nodes/machines/control_flow.py +10 -0
  7. griptape_nodes/machines/dag_builder.py +21 -2
  8. griptape_nodes/machines/parallel_resolution.py +25 -10
  9. griptape_nodes/node_library/workflow_registry.py +73 -3
  10. griptape_nodes/retained_mode/events/execution_events.py +12 -2
  11. griptape_nodes/retained_mode/events/flow_events.py +58 -0
  12. griptape_nodes/retained_mode/events/resource_events.py +290 -0
  13. griptape_nodes/retained_mode/events/workflow_events.py +57 -2
  14. griptape_nodes/retained_mode/griptape_nodes.py +9 -1
  15. griptape_nodes/retained_mode/managers/flow_manager.py +678 -12
  16. griptape_nodes/retained_mode/managers/library_manager.py +13 -19
  17. griptape_nodes/retained_mode/managers/model_manager.py +184 -83
  18. griptape_nodes/retained_mode/managers/node_manager.py +3 -3
  19. griptape_nodes/retained_mode/managers/os_manager.py +118 -1
  20. griptape_nodes/retained_mode/managers/resource_components/__init__.py +1 -0
  21. griptape_nodes/retained_mode/managers/resource_components/capability_field.py +41 -0
  22. griptape_nodes/retained_mode/managers/resource_components/comparator.py +18 -0
  23. griptape_nodes/retained_mode/managers/resource_components/resource_instance.py +236 -0
  24. griptape_nodes/retained_mode/managers/resource_components/resource_type.py +79 -0
  25. griptape_nodes/retained_mode/managers/resource_manager.py +306 -0
  26. griptape_nodes/retained_mode/managers/resource_types/__init__.py +1 -0
  27. griptape_nodes/retained_mode/managers/resource_types/cpu_resource.py +108 -0
  28. griptape_nodes/retained_mode/managers/resource_types/os_resource.py +87 -0
  29. griptape_nodes/retained_mode/managers/settings.py +5 -0
  30. griptape_nodes/retained_mode/managers/sync_manager.py +10 -3
  31. griptape_nodes/retained_mode/managers/workflow_manager.py +359 -261
  32. {griptape_nodes-0.55.1.dist-info → griptape_nodes-0.56.0.dist-info}/METADATA +1 -1
  33. {griptape_nodes-0.55.1.dist-info → griptape_nodes-0.56.0.dist-info}/RECORD +35 -25
  34. {griptape_nodes-0.55.1.dist-info → griptape_nodes-0.56.0.dist-info}/WHEEL +1 -1
  35. {griptape_nodes-0.55.1.dist-info → griptape_nodes-0.56.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,108 @@
1
+ import logging
2
+ from typing import TYPE_CHECKING, Any, Literal
3
+
4
+ from griptape_nodes.retained_mode.managers.resource_components.capability_field import (
5
+ CapabilityField,
6
+ validate_capabilities,
7
+ )
8
+ from griptape_nodes.retained_mode.managers.resource_components.resource_instance import ResourceInstance
9
+ from griptape_nodes.retained_mode.managers.resource_components.resource_type import ResourceType
10
+
11
+ if TYPE_CHECKING:
12
+ from griptape_nodes.retained_mode.managers.resource_components.resource_instance import Requirements
13
+
14
+ logger = logging.getLogger("griptape_nodes")
15
+
16
+
17
+ # CPU capability field names
18
+ CPUCapability = Literal[
19
+ "cores",
20
+ "threads",
21
+ "architecture",
22
+ "clock_speed_ghz",
23
+ ]
24
+
25
+
26
+ class CPUInstance(ResourceInstance):
27
+ """Resource instance representing CPU compute resources."""
28
+
29
+ def can_be_freed(self) -> bool:
30
+ """CPU resources can typically be freed when not in use."""
31
+ return True
32
+
33
+ def free(self) -> None:
34
+ """Free CPU resource instance."""
35
+ logger.debug("Freeing CPU resource instance %s", self.get_instance_id())
36
+
37
+ def get_capability_typed(self, key: CPUCapability) -> Any:
38
+ """Type-safe capability getter using Literal types."""
39
+ return self.get_capability_value(key)
40
+
41
+
42
+ class CPUResourceType(ResourceType):
43
+ """Resource type for CPU compute resources."""
44
+
45
+ def get_capability_schema(self) -> list[CapabilityField]:
46
+ """Get the capability schema for CPU resources."""
47
+ return [
48
+ CapabilityField(
49
+ name="cores",
50
+ type_hint=int,
51
+ description="Number of CPU cores",
52
+ required=True,
53
+ ),
54
+ CapabilityField(
55
+ name="threads",
56
+ type_hint=int,
57
+ description="Number of threads (with hyperthreading)",
58
+ required=False,
59
+ ),
60
+ CapabilityField(
61
+ name="architecture",
62
+ type_hint=str,
63
+ description="CPU architecture: 'x86_64', 'arm64', 'aarch64'",
64
+ required=True,
65
+ ),
66
+ CapabilityField(
67
+ name="clock_speed_ghz",
68
+ type_hint=float,
69
+ description="Base clock speed in GHz",
70
+ required=False,
71
+ ),
72
+ ]
73
+
74
+ def create_instance(self, capabilities: dict[str, Any]) -> ResourceInstance:
75
+ """Create a new CPU resource instance."""
76
+ # Validate capabilities against schema
77
+ validation_errors = validate_capabilities(self.get_capability_schema(), capabilities)
78
+ if validation_errors:
79
+ error_msg = f"Invalid CPU capabilities: {', '.join(validation_errors)}"
80
+ raise ValueError(error_msg)
81
+
82
+ return CPUInstance(resource_type=self, instance_id_prefix="cpu", capabilities=capabilities)
83
+
84
+ def select_best_compatible_instance(
85
+ self, compatible_instances: list[ResourceInstance], _requirements: "Requirements | None" = None
86
+ ) -> ResourceInstance | None:
87
+ """Select the best CPU instance from compatible ones.
88
+
89
+ Prioritizes CPUs with:
90
+ 1. More cores
91
+ 2. Higher clock speed
92
+ """
93
+ if not compatible_instances:
94
+ return None
95
+
96
+ def sort_key(instance: ResourceInstance) -> tuple[int, float]:
97
+ # More cores is better
98
+ cores = instance.get_capability_value("cores") if instance.has_capability("cores") else 1
99
+
100
+ # Higher clock speed is better
101
+ clock_speed = (
102
+ instance.get_capability_value("clock_speed_ghz") if instance.has_capability("clock_speed_ghz") else 0
103
+ )
104
+
105
+ return (int(cores), float(clock_speed))
106
+
107
+ sorted_instances = sorted(compatible_instances, key=sort_key, reverse=True)
108
+ return sorted_instances[0]
@@ -0,0 +1,87 @@
1
+ import logging
2
+ from typing import TYPE_CHECKING, Any, Literal
3
+
4
+ from griptape_nodes.retained_mode.managers.resource_components.capability_field import (
5
+ CapabilityField,
6
+ validate_capabilities,
7
+ )
8
+ from griptape_nodes.retained_mode.managers.resource_components.resource_instance import ResourceInstance
9
+ from griptape_nodes.retained_mode.managers.resource_components.resource_type import ResourceType
10
+
11
+ if TYPE_CHECKING:
12
+ from griptape_nodes.retained_mode.managers.resource_components.resource_instance import Requirements
13
+
14
+ logger = logging.getLogger("griptape_nodes")
15
+
16
+
17
+ # OS capability field names
18
+ OSCapability = Literal[
19
+ "platform",
20
+ "arch",
21
+ "version",
22
+ ]
23
+
24
+
25
+ class OSInstance(ResourceInstance):
26
+ """Resource instance representing an operating system environment."""
27
+
28
+ def can_be_freed(self) -> bool:
29
+ """OS resources can be freed when no longer needed."""
30
+ return True
31
+
32
+ def free(self) -> None:
33
+ """Free OS resource instance."""
34
+ logger.debug("Freeing OS resource instance %s", self.get_instance_id())
35
+
36
+ def get_capability_typed(self, key: OSCapability) -> Any:
37
+ """Type-safe capability getter using Literal types."""
38
+ return self.get_capability_value(key)
39
+
40
+
41
+ class OSResourceType(ResourceType):
42
+ """Resource type for operating system environments."""
43
+
44
+ def get_capability_schema(self) -> list[CapabilityField]:
45
+ """Get the capability schema for OS resources."""
46
+ return [
47
+ CapabilityField(
48
+ name="platform",
49
+ type_hint=str,
50
+ description="Operating system platform: 'linux', 'darwin', 'windows'",
51
+ required=True,
52
+ ),
53
+ CapabilityField(
54
+ name="arch",
55
+ type_hint=str,
56
+ description="System architecture: 'x86_64', 'arm64', 'aarch64'",
57
+ required=True,
58
+ ),
59
+ CapabilityField(
60
+ name="version",
61
+ type_hint=str,
62
+ description="Operating system version string",
63
+ required=False,
64
+ ),
65
+ ]
66
+
67
+ def create_instance(self, capabilities: dict[str, Any]) -> ResourceInstance:
68
+ """Create a new OS resource instance."""
69
+ # Validate capabilities against schema
70
+ validation_errors = validate_capabilities(self.get_capability_schema(), capabilities)
71
+ if validation_errors:
72
+ error_msg = f"Invalid OS capabilities: {', '.join(validation_errors)}"
73
+ raise ValueError(error_msg)
74
+
75
+ return OSInstance(resource_type=self, instance_id_prefix="os", capabilities=capabilities)
76
+
77
+ def select_best_compatible_instance(
78
+ self, compatible_instances: list[ResourceInstance], _requirements: "Requirements | None" = None
79
+ ) -> ResourceInstance | None:
80
+ """Select the best OS instance from compatible ones.
81
+
82
+ Returns the first compatible instance (no special selection criteria for now).
83
+ """
84
+ if not compatible_instances:
85
+ return None
86
+
87
+ return compatible_instances[0]
@@ -210,3 +210,8 @@ class Settings(BaseModel):
210
210
  default="synced_workflows",
211
211
  description="Path to the synced workflows directory, relative to the workspace directory.",
212
212
  )
213
+ enable_workspace_file_watching: bool = Field(
214
+ category=FILE_SYSTEM,
215
+ default=True,
216
+ description="Enable file watching for synced workflows directory",
217
+ )
@@ -164,8 +164,15 @@ class SyncManager:
164
164
  try:
165
165
  # Check if cloud storage is configured before attempting sync
166
166
  self._get_cloud_storage_driver()
167
- # Start file watching after successful sync
168
- self._start_file_watching()
167
+
168
+ # Check if file watching is enabled before starting it
169
+ enable_file_watching = self._config_manager.get_config_value("enable_workspace_file_watching", default=True)
170
+ if enable_file_watching:
171
+ # Start file watching after successful sync
172
+ self._start_file_watching()
173
+ logger.debug("File watching enabled - started watching synced workflows directory")
174
+ else:
175
+ logger.debug("File watching disabled - skipping file watching startup")
169
176
 
170
177
  logger.info("App initialization complete - starting automatic cloud workflow sync")
171
178
 
@@ -449,7 +456,7 @@ class SyncManager:
449
456
 
450
457
  # Collect results as they complete
451
458
  for future in future_to_filename:
452
- filename, success, error = future.result()
459
+ filename, success, _error = future.result()
453
460
  if success:
454
461
  synced_workflows.append(filename)
455
462
  else: