griptape-nodes 0.55.0__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.
- griptape_nodes/cli/commands/init.py +88 -0
- griptape_nodes/cli/commands/models.py +2 -0
- griptape_nodes/cli/shared.py +1 -0
- griptape_nodes/exe_types/core_types.py +104 -5
- griptape_nodes/exe_types/node_types.py +9 -12
- griptape_nodes/machines/control_flow.py +10 -0
- griptape_nodes/machines/dag_builder.py +21 -2
- griptape_nodes/machines/parallel_resolution.py +25 -10
- griptape_nodes/node_library/workflow_registry.py +73 -3
- griptape_nodes/retained_mode/events/execution_events.py +12 -2
- griptape_nodes/retained_mode/events/flow_events.py +58 -0
- griptape_nodes/retained_mode/events/resource_events.py +290 -0
- griptape_nodes/retained_mode/events/workflow_events.py +57 -2
- griptape_nodes/retained_mode/griptape_nodes.py +9 -1
- griptape_nodes/retained_mode/managers/flow_manager.py +678 -12
- griptape_nodes/retained_mode/managers/library_manager.py +13 -19
- griptape_nodes/retained_mode/managers/model_manager.py +184 -83
- griptape_nodes/retained_mode/managers/node_manager.py +3 -3
- griptape_nodes/retained_mode/managers/os_manager.py +118 -1
- griptape_nodes/retained_mode/managers/resource_components/__init__.py +1 -0
- griptape_nodes/retained_mode/managers/resource_components/capability_field.py +41 -0
- griptape_nodes/retained_mode/managers/resource_components/comparator.py +18 -0
- griptape_nodes/retained_mode/managers/resource_components/resource_instance.py +236 -0
- griptape_nodes/retained_mode/managers/resource_components/resource_type.py +79 -0
- griptape_nodes/retained_mode/managers/resource_manager.py +306 -0
- griptape_nodes/retained_mode/managers/resource_types/__init__.py +1 -0
- griptape_nodes/retained_mode/managers/resource_types/cpu_resource.py +108 -0
- griptape_nodes/retained_mode/managers/resource_types/os_resource.py +87 -0
- griptape_nodes/retained_mode/managers/settings.py +5 -0
- griptape_nodes/retained_mode/managers/sync_manager.py +10 -3
- griptape_nodes/retained_mode/managers/workflow_manager.py +359 -261
- {griptape_nodes-0.55.0.dist-info → griptape_nodes-0.56.0.dist-info}/METADATA +1 -1
- {griptape_nodes-0.55.0.dist-info → griptape_nodes-0.56.0.dist-info}/RECORD +35 -25
- {griptape_nodes-0.55.0.dist-info → griptape_nodes-0.56.0.dist-info}/WHEEL +1 -1
- {griptape_nodes-0.55.0.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
|
-
|
|
168
|
-
|
|
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,
|
|
459
|
+
filename, success, _error = future.result()
|
|
453
460
|
if success:
|
|
454
461
|
synced_workflows.append(filename)
|
|
455
462
|
else:
|