griptape-nodes 0.70.1__py3-none-any.whl → 0.72.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/api_client/client.py +8 -5
- griptape_nodes/app/app.py +4 -0
- griptape_nodes/bootstrap/utils/python_subprocess_executor.py +48 -9
- griptape_nodes/bootstrap/utils/subprocess_websocket_base.py +88 -0
- griptape_nodes/bootstrap/utils/subprocess_websocket_listener.py +126 -0
- griptape_nodes/bootstrap/utils/subprocess_websocket_sender.py +121 -0
- griptape_nodes/bootstrap/workflow_executors/local_session_workflow_executor.py +17 -170
- griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +10 -1
- griptape_nodes/bootstrap/workflow_executors/subprocess_workflow_executor.py +13 -117
- griptape_nodes/bootstrap/workflow_executors/utils/subprocess_script.py +4 -0
- griptape_nodes/bootstrap/workflow_publishers/local_session_workflow_publisher.py +206 -0
- griptape_nodes/bootstrap/workflow_publishers/subprocess_workflow_publisher.py +22 -3
- griptape_nodes/bootstrap/workflow_publishers/utils/subprocess_script.py +49 -25
- griptape_nodes/common/node_executor.py +61 -14
- griptape_nodes/drivers/image_metadata/__init__.py +21 -0
- griptape_nodes/drivers/image_metadata/base_image_metadata_driver.py +63 -0
- griptape_nodes/drivers/image_metadata/exif_metadata_driver.py +218 -0
- griptape_nodes/drivers/image_metadata/image_metadata_driver_registry.py +55 -0
- griptape_nodes/drivers/image_metadata/png_metadata_driver.py +71 -0
- griptape_nodes/drivers/storage/base_storage_driver.py +32 -0
- griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +384 -10
- griptape_nodes/drivers/storage/local_storage_driver.py +65 -4
- griptape_nodes/drivers/thread_storage/local_thread_storage_driver.py +1 -0
- griptape_nodes/exe_types/base_iterative_nodes.py +1 -1
- griptape_nodes/exe_types/node_groups/base_node_group.py +3 -0
- griptape_nodes/exe_types/node_groups/subflow_node_group.py +18 -0
- griptape_nodes/exe_types/node_types.py +13 -0
- griptape_nodes/exe_types/param_components/log_parameter.py +4 -4
- griptape_nodes/exe_types/param_components/subflow_execution_component.py +329 -0
- griptape_nodes/exe_types/param_types/parameter_audio.py +17 -2
- griptape_nodes/exe_types/param_types/parameter_float.py +4 -4
- griptape_nodes/exe_types/param_types/parameter_image.py +14 -1
- griptape_nodes/exe_types/param_types/parameter_int.py +4 -4
- griptape_nodes/exe_types/param_types/parameter_number.py +12 -14
- griptape_nodes/exe_types/param_types/parameter_three_d.py +14 -1
- griptape_nodes/exe_types/param_types/parameter_video.py +17 -2
- griptape_nodes/node_library/workflow_registry.py +5 -8
- griptape_nodes/retained_mode/events/app_events.py +1 -0
- griptape_nodes/retained_mode/events/base_events.py +42 -26
- griptape_nodes/retained_mode/events/flow_events.py +67 -0
- griptape_nodes/retained_mode/events/library_events.py +1 -1
- griptape_nodes/retained_mode/events/node_events.py +1 -0
- griptape_nodes/retained_mode/events/os_events.py +22 -0
- griptape_nodes/retained_mode/events/static_file_events.py +28 -4
- griptape_nodes/retained_mode/managers/flow_manager.py +134 -0
- griptape_nodes/retained_mode/managers/image_metadata_injector.py +339 -0
- griptape_nodes/retained_mode/managers/library_manager.py +71 -41
- griptape_nodes/retained_mode/managers/model_manager.py +1 -0
- griptape_nodes/retained_mode/managers/node_manager.py +8 -5
- griptape_nodes/retained_mode/managers/os_manager.py +270 -33
- griptape_nodes/retained_mode/managers/project_manager.py +3 -7
- griptape_nodes/retained_mode/managers/session_manager.py +1 -0
- griptape_nodes/retained_mode/managers/settings.py +5 -0
- griptape_nodes/retained_mode/managers/static_files_manager.py +83 -17
- griptape_nodes/retained_mode/managers/workflow_manager.py +71 -41
- griptape_nodes/servers/static.py +31 -0
- griptape_nodes/utils/__init__.py +9 -1
- griptape_nodes/utils/artifact_normalization.py +245 -0
- griptape_nodes/utils/file_utils.py +13 -13
- griptape_nodes/utils/http_file_patch.py +613 -0
- griptape_nodes/utils/image_preview.py +27 -0
- griptape_nodes/utils/path_utils.py +58 -0
- griptape_nodes/utils/url_utils.py +106 -0
- {griptape_nodes-0.70.1.dist-info → griptape_nodes-0.72.0.dist-info}/METADATA +2 -1
- {griptape_nodes-0.70.1.dist-info → griptape_nodes-0.72.0.dist-info}/RECORD +67 -52
- {griptape_nodes-0.70.1.dist-info → griptape_nodes-0.72.0.dist-info}/WHEEL +1 -1
- {griptape_nodes-0.70.1.dist-info → griptape_nodes-0.72.0.dist-info}/entry_points.txt +0 -0
|
@@ -43,8 +43,8 @@ class ParameterInt(ParameterNumber):
|
|
|
43
43
|
ui_options: dict | None = None,
|
|
44
44
|
step: int | None = None,
|
|
45
45
|
slider: bool = False,
|
|
46
|
-
min_val: float =
|
|
47
|
-
max_val: float =
|
|
46
|
+
min_val: float | None = None,
|
|
47
|
+
max_val: float | None = None,
|
|
48
48
|
validate_min_max: bool = False,
|
|
49
49
|
accept_any: bool = True,
|
|
50
50
|
hide: bool | None = None,
|
|
@@ -77,8 +77,8 @@ class ParameterInt(ParameterNumber):
|
|
|
77
77
|
ui_options: Dictionary of UI options
|
|
78
78
|
step: Step size for numeric input controls
|
|
79
79
|
slider: Whether to use slider trait
|
|
80
|
-
min_val: Minimum value for constraints
|
|
81
|
-
max_val: Maximum value for constraints
|
|
80
|
+
min_val: Minimum value for constraints (None to disable constraints)
|
|
81
|
+
max_val: Maximum value for constraints (None to disable constraints)
|
|
82
82
|
validate_min_max: Whether to validate min/max with error
|
|
83
83
|
accept_any: Whether to accept any input type and convert to integer (default: True)
|
|
84
84
|
hide: Whether to hide the entire parameter
|
|
@@ -37,8 +37,8 @@ class ParameterNumber(Parameter):
|
|
|
37
37
|
ui_options: dict | None = None,
|
|
38
38
|
step: float | None = None,
|
|
39
39
|
slider: bool = False,
|
|
40
|
-
min_val: float =
|
|
41
|
-
max_val: float =
|
|
40
|
+
min_val: float | None = None,
|
|
41
|
+
max_val: float | None = None,
|
|
42
42
|
validate_min_max: bool = False,
|
|
43
43
|
accept_any: bool = True,
|
|
44
44
|
hide: bool | None = None,
|
|
@@ -74,8 +74,8 @@ class ParameterNumber(Parameter):
|
|
|
74
74
|
ui_options: Dictionary of UI options
|
|
75
75
|
step: Step size for numeric input controls
|
|
76
76
|
slider: Whether to use slider trait
|
|
77
|
-
min_val: Minimum value for constraints
|
|
78
|
-
max_val: Maximum value for constraints
|
|
77
|
+
min_val: Minimum value for constraints (None to disable constraints)
|
|
78
|
+
max_val: Maximum value for constraints (None to disable constraints)
|
|
79
79
|
validate_min_max: Whether to validate min/max with error
|
|
80
80
|
accept_any: Whether to accept any input type and convert to number (default: True)
|
|
81
81
|
hide: Whether to hide the entire parameter
|
|
@@ -220,8 +220,8 @@ class ParameterNumber(Parameter):
|
|
|
220
220
|
traits: set[type[Trait] | Trait] | None,
|
|
221
221
|
*,
|
|
222
222
|
slider: bool,
|
|
223
|
-
min_val: float,
|
|
224
|
-
max_val: float,
|
|
223
|
+
min_val: float | None,
|
|
224
|
+
max_val: float | None,
|
|
225
225
|
validate_min_max: bool,
|
|
226
226
|
) -> None:
|
|
227
227
|
"""Set up constraint traits based on parameters.
|
|
@@ -272,14 +272,14 @@ class ParameterNumber(Parameter):
|
|
|
272
272
|
def slider(self, value: bool) -> None:
|
|
273
273
|
"""Set slider trait."""
|
|
274
274
|
if value:
|
|
275
|
-
|
|
275
|
+
# Get min/max from stored values
|
|
276
|
+
min_val = getattr(self, "_min_val", None)
|
|
277
|
+
max_val = getattr(self, "_max_val", None)
|
|
278
|
+
if min_val is None or max_val is None:
|
|
276
279
|
msg = f"{self.name}: Cannot enable slider without min_val and max_val"
|
|
277
280
|
raise ValueError(msg)
|
|
278
281
|
# Find existing constraint traits and replace with slider
|
|
279
282
|
self._remove_constraint_traits()
|
|
280
|
-
# Get min/max from existing traits or use defaults
|
|
281
|
-
min_val = getattr(self, "_min_val", 0)
|
|
282
|
-
max_val = getattr(self, "_max_val", 100)
|
|
283
283
|
self.add_trait(Slider(min_val=min_val, max_val=max_val))
|
|
284
284
|
else:
|
|
285
285
|
# Remove slider trait
|
|
@@ -325,14 +325,12 @@ class ParameterNumber(Parameter):
|
|
|
325
325
|
"""Set MinMax validation."""
|
|
326
326
|
if value:
|
|
327
327
|
# Check if we have stored min/max values
|
|
328
|
-
min_val
|
|
329
|
-
max_val = getattr(self, "_max_val", None)
|
|
330
|
-
if min_val is None or max_val is None:
|
|
328
|
+
if self.min_val is None or self.max_val is None:
|
|
331
329
|
msg = f"{self.name}: Cannot enable validate_min_max without min_val and max_val"
|
|
332
330
|
raise ValueError(msg)
|
|
333
331
|
# Replace existing constraint traits with MinMax
|
|
334
332
|
self._remove_constraint_traits()
|
|
335
|
-
self.add_trait(MinMax(min_val=min_val, max_val=max_val))
|
|
333
|
+
self.add_trait(MinMax(min_val=self.min_val, max_val=self.max_val))
|
|
336
334
|
else:
|
|
337
335
|
# Remove MinMax trait and replace with Clamp if we have min/max
|
|
338
336
|
min_max_traits = self.find_elements_by_type(MinMax)
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
+
from griptape_nodes_library.three_d.three_d_artifact import ThreeDUrlArtifact # pyright: ignore[reportMissingImports]
|
|
7
|
+
|
|
6
8
|
from griptape_nodes.exe_types.core_types import Parameter, ParameterMode, Trait
|
|
9
|
+
from griptape_nodes.utils.artifact_normalization import normalize_artifact_input
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
class Parameter3D(Parameter):
|
|
@@ -117,6 +120,16 @@ class Parameter3D(Parameter):
|
|
|
117
120
|
else:
|
|
118
121
|
final_input_types = ["ThreeDUrlArtifact"]
|
|
119
122
|
|
|
123
|
+
# Add automatic converter to normalize string inputs to ThreeDUrlArtifact
|
|
124
|
+
# This allows Parameter3D to automatically handle file paths and localhost URLs
|
|
125
|
+
three_d_converters = list(converters) if converters else []
|
|
126
|
+
if accept_any:
|
|
127
|
+
# Create a converter function that uses normalize_artifact_input with ThreeDUrlArtifact
|
|
128
|
+
def _normalize_three_d(value: Any) -> Any:
|
|
129
|
+
return normalize_artifact_input(value, ThreeDUrlArtifact)
|
|
130
|
+
|
|
131
|
+
three_d_converters.insert(0, _normalize_three_d)
|
|
132
|
+
|
|
120
133
|
# Call parent with explicit parameters, following ControlParameter pattern
|
|
121
134
|
super().__init__(
|
|
122
135
|
name=name,
|
|
@@ -130,7 +143,7 @@ class Parameter3D(Parameter):
|
|
|
130
143
|
tooltip_as_output=tooltip_as_output,
|
|
131
144
|
allowed_modes=allowed_modes,
|
|
132
145
|
traits=traits,
|
|
133
|
-
converters=
|
|
146
|
+
converters=three_d_converters,
|
|
134
147
|
validators=validators,
|
|
135
148
|
ui_options=ui_options,
|
|
136
149
|
hide=hide,
|
|
@@ -4,6 +4,7 @@ from collections.abc import Callable
|
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
6
|
from griptape_nodes.exe_types.core_types import Parameter, ParameterMode, Trait
|
|
7
|
+
from griptape_nodes.utils.artifact_normalization import normalize_artifact_input
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class ParameterVideo(Parameter):
|
|
@@ -24,7 +25,7 @@ class ParameterVideo(Parameter):
|
|
|
24
25
|
param.pulse_on_run = True # Change UI options at runtime
|
|
25
26
|
"""
|
|
26
27
|
|
|
27
|
-
def __init__( # noqa: PLR0913
|
|
28
|
+
def __init__( # noqa: C901, PLR0913
|
|
28
29
|
self,
|
|
29
30
|
name: str,
|
|
30
31
|
tooltip: str | None = None,
|
|
@@ -122,6 +123,20 @@ class ParameterVideo(Parameter):
|
|
|
122
123
|
else:
|
|
123
124
|
final_input_types = ["VideoUrlArtifact"]
|
|
124
125
|
|
|
126
|
+
# Add automatic converter to normalize string inputs to VideoUrlArtifact
|
|
127
|
+
# This allows ParameterVideo to automatically handle file paths and localhost URLs
|
|
128
|
+
video_converters = list(converters) if converters else []
|
|
129
|
+
if accept_any:
|
|
130
|
+
# Create a converter function that uses normalize_artifact_input with VideoUrlArtifact
|
|
131
|
+
def _normalize_video(value: Any) -> Any:
|
|
132
|
+
try:
|
|
133
|
+
from griptape.artifacts import VideoUrlArtifact
|
|
134
|
+
except ImportError:
|
|
135
|
+
return value
|
|
136
|
+
return normalize_artifact_input(value, VideoUrlArtifact)
|
|
137
|
+
|
|
138
|
+
video_converters.insert(0, _normalize_video)
|
|
139
|
+
|
|
125
140
|
# Call parent with explicit parameters, following ControlParameter pattern
|
|
126
141
|
super().__init__(
|
|
127
142
|
name=name,
|
|
@@ -135,7 +150,7 @@ class ParameterVideo(Parameter):
|
|
|
135
150
|
tooltip_as_output=tooltip_as_output,
|
|
136
151
|
allowed_modes=allowed_modes,
|
|
137
152
|
traits=traits,
|
|
138
|
-
converters=
|
|
153
|
+
converters=video_converters,
|
|
139
154
|
validators=validators,
|
|
140
155
|
ui_options=ui_options,
|
|
141
156
|
hide=hide,
|
|
@@ -12,6 +12,7 @@ from griptape_nodes.node_library.library_registry import (
|
|
|
12
12
|
LibraryNameAndVersion, # noqa: TC001 (putting this into type checking causes it to not be defined)
|
|
13
13
|
)
|
|
14
14
|
from griptape_nodes.utils.metaclasses import SingletonMeta
|
|
15
|
+
from griptape_nodes.utils.path_utils import resolve_workspace_path
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger("griptape_nodes")
|
|
17
18
|
|
|
@@ -45,7 +46,7 @@ class WorkflowShape(BaseModel):
|
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
class WorkflowMetadata(BaseModel):
|
|
48
|
-
LATEST_SCHEMA_VERSION: ClassVar[str] = "0.
|
|
49
|
+
LATEST_SCHEMA_VERSION: ClassVar[str] = "0.15.0"
|
|
49
50
|
|
|
50
51
|
name: str
|
|
51
52
|
schema_version: str
|
|
@@ -175,15 +176,11 @@ class WorkflowRegistry(metaclass=SingletonMeta):
|
|
|
175
176
|
def get_complete_file_path(cls, relative_file_path: str) -> str:
|
|
176
177
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
177
178
|
|
|
178
|
-
#
|
|
179
|
-
if Path(relative_file_path).is_absolute():
|
|
180
|
-
return relative_file_path
|
|
181
|
-
|
|
182
|
-
# Otherwise, resolve it relative to the workspace
|
|
179
|
+
# Resolve path using utility function
|
|
183
180
|
config_mgr = GriptapeNodes.ConfigManager()
|
|
184
181
|
workspace_path = config_mgr.workspace_path
|
|
185
|
-
|
|
186
|
-
return str(
|
|
182
|
+
resolved_path = resolve_workspace_path(Path(relative_file_path), workspace_path)
|
|
183
|
+
return str(resolved_path)
|
|
187
184
|
|
|
188
185
|
@classmethod
|
|
189
186
|
def delete_workflow_by_name(cls, name: str) -> Workflow:
|
|
@@ -113,6 +113,7 @@ class AppInitializationComplete(AppPayload):
|
|
|
113
113
|
libraries_to_register: list[str] = field(default_factory=list)
|
|
114
114
|
workflows_to_register: list[str] = field(default_factory=list)
|
|
115
115
|
models_to_download: list[str] = field(default_factory=list)
|
|
116
|
+
skip_library_loading: bool = False
|
|
116
117
|
|
|
117
118
|
|
|
118
119
|
@dataclass
|
|
@@ -16,6 +16,31 @@ if TYPE_CHECKING:
|
|
|
16
16
|
import builtins
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
def default_json_encoder(obj: Any) -> Any:
|
|
20
|
+
"""Custom JSON encoder for various object types.
|
|
21
|
+
|
|
22
|
+
Attempts the following encodings in order:
|
|
23
|
+
1. If the object is a SerializableMixin, call to_dict()
|
|
24
|
+
2. If the object is a Pydantic model, call model_dump()
|
|
25
|
+
3. Attempt to use the default JSON encoder
|
|
26
|
+
4. If all else fails, return the string representation of the object
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
obj: The object to encode
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
JSON-serializable representation of the object
|
|
33
|
+
"""
|
|
34
|
+
if isinstance(obj, SerializableMixin):
|
|
35
|
+
return obj.to_dict()
|
|
36
|
+
if isinstance(obj, BaseModel):
|
|
37
|
+
return obj.model_dump()
|
|
38
|
+
try:
|
|
39
|
+
return json.JSONEncoder().default(obj)
|
|
40
|
+
except TypeError:
|
|
41
|
+
return str(obj)
|
|
42
|
+
|
|
43
|
+
|
|
19
44
|
@dataclass
|
|
20
45
|
class ResultDetail:
|
|
21
46
|
"""A single detail about an operation result, including logging level and human readable message."""
|
|
@@ -71,6 +96,22 @@ class ResultDetails:
|
|
|
71
96
|
class Payload(ABC): # noqa: B024
|
|
72
97
|
"""Base class for all payload types. Customers will derive from this."""
|
|
73
98
|
|
|
99
|
+
def to_json(self, **kwargs) -> str:
|
|
100
|
+
"""Serialize this payload to JSON string.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
JSON string representation of the payload
|
|
104
|
+
"""
|
|
105
|
+
# Convert payload to dict
|
|
106
|
+
if is_dataclass(self):
|
|
107
|
+
payload_dict = asdict(self)
|
|
108
|
+
elif hasattr(self, "__dict__"):
|
|
109
|
+
payload_dict = self.__dict__
|
|
110
|
+
else:
|
|
111
|
+
payload_dict = str(self)
|
|
112
|
+
|
|
113
|
+
return json.dumps(payload_dict, default=default_json_encoder, **kwargs)
|
|
114
|
+
|
|
74
115
|
|
|
75
116
|
# Request payload base class with optional request ID
|
|
76
117
|
@dataclass(kw_only=True)
|
|
@@ -228,32 +269,7 @@ class BaseEvent(BaseModel, ABC):
|
|
|
228
269
|
|
|
229
270
|
def json(self, **kwargs) -> str:
|
|
230
271
|
"""Serialize to JSON string."""
|
|
231
|
-
|
|
232
|
-
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/906
|
|
233
|
-
def default_encoder(obj: Any) -> Any:
|
|
234
|
-
"""Custom JSON encoder for various object types.
|
|
235
|
-
|
|
236
|
-
Attempts the following encodings in order:
|
|
237
|
-
1. If the object is a SerializableMixin, call to_dict()
|
|
238
|
-
2. If the object is a Pydantic model, call model_dump()
|
|
239
|
-
3. Attempt to use the default JSON encoder
|
|
240
|
-
4. If all else fails, return the string representation of the object
|
|
241
|
-
|
|
242
|
-
Args:
|
|
243
|
-
obj: The object to encode
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
"""
|
|
247
|
-
if isinstance(obj, SerializableMixin):
|
|
248
|
-
return obj.to_dict()
|
|
249
|
-
if isinstance(obj, BaseModel):
|
|
250
|
-
return obj.model_dump()
|
|
251
|
-
try:
|
|
252
|
-
return json.JSONEncoder().default(obj)
|
|
253
|
-
except TypeError:
|
|
254
|
-
return str(obj)
|
|
255
|
-
|
|
256
|
-
return json.dumps(self.dict(), default=default_encoder, **kwargs)
|
|
272
|
+
return json.dumps(self.dict(), default=default_json_encoder, **kwargs)
|
|
257
273
|
|
|
258
274
|
@abstractmethod
|
|
259
275
|
def get_request(self) -> Payload:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
+
from enum import StrEnum
|
|
4
5
|
from typing import TYPE_CHECKING, Any, NamedTuple
|
|
5
6
|
|
|
6
7
|
if TYPE_CHECKING:
|
|
@@ -19,6 +20,18 @@ from griptape_nodes.retained_mode.events.base_events import (
|
|
|
19
20
|
from griptape_nodes.retained_mode.events.payload_registry import PayloadRegistry
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
class FlowMetadataExtractionFailureReason(StrEnum):
|
|
24
|
+
"""Reasons why flow metadata extraction from image failed."""
|
|
25
|
+
|
|
26
|
+
FILE_NOT_FOUND = "file_not_found"
|
|
27
|
+
FILE_READ_ERROR = "file_read_error"
|
|
28
|
+
INVALID_IMAGE_FORMAT = "invalid_image_format"
|
|
29
|
+
NO_FLOW_METADATA = "no_flow_metadata"
|
|
30
|
+
INVALID_BASE64 = "invalid_base64"
|
|
31
|
+
INVALID_PICKLE = "invalid_pickle"
|
|
32
|
+
DESERIALIZATION_FAILED = "deserialization_failed"
|
|
33
|
+
|
|
34
|
+
|
|
22
35
|
@dataclass(kw_only=True)
|
|
23
36
|
@PayloadRegistry.register
|
|
24
37
|
class CreateFlowRequest(RequestPayload):
|
|
@@ -288,6 +301,60 @@ class DeserializeFlowFromCommandsResultFailure(ResultPayloadFailure):
|
|
|
288
301
|
pass
|
|
289
302
|
|
|
290
303
|
|
|
304
|
+
@dataclass
|
|
305
|
+
@PayloadRegistry.register
|
|
306
|
+
class ExtractFlowCommandsFromImageMetadataRequest(RequestPayload):
|
|
307
|
+
"""Extract flow commands from PNG image metadata.
|
|
308
|
+
|
|
309
|
+
This request reads a PNG image file, extracts the embedded workflow metadata
|
|
310
|
+
(specifically the gtn_flow_commands field), decodes it from base64, unpickles it,
|
|
311
|
+
and returns the SerializedFlowCommands object. Optionally, it can automatically
|
|
312
|
+
deserialize the flow by calling DeserializeFlowFromCommandsRequest.
|
|
313
|
+
|
|
314
|
+
Use when: Loading flow commands from an exported image, inspecting workflow
|
|
315
|
+
structure before deserialization, extracting flows shared as PNG files.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
file_url_or_path: Path to the PNG image file (absolute or relative) or URL
|
|
319
|
+
deserialize: If True, automatically deserialize the flow after extraction (default: False)
|
|
320
|
+
|
|
321
|
+
Results:
|
|
322
|
+
ExtractFlowCommandsFromImageMetadataResultSuccess - Commands extracted (and optionally deserialized)
|
|
323
|
+
ExtractFlowCommandsFromImageMetadataResultFailure - Extraction or deserialization failed
|
|
324
|
+
"""
|
|
325
|
+
|
|
326
|
+
file_url_or_path: str
|
|
327
|
+
deserialize: bool = False
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
@dataclass(kw_only=True)
|
|
331
|
+
@PayloadRegistry.register
|
|
332
|
+
class ExtractFlowCommandsFromImageMetadataResultSuccess(ResultPayloadSuccess):
|
|
333
|
+
"""Flow commands extracted successfully from image metadata.
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
serialized_flow_commands: The extracted and decoded SerializedFlowCommands object
|
|
337
|
+
flow_name: Name of the deserialized flow (only present if deserialize=True)
|
|
338
|
+
node_name_mappings: Mapping from original to deserialized node names (only present if deserialize=True)
|
|
339
|
+
"""
|
|
340
|
+
|
|
341
|
+
serialized_flow_commands: SerializedFlowCommands
|
|
342
|
+
flow_name: str | None = None
|
|
343
|
+
node_name_mappings: dict[str, str] = field(default_factory=dict)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
@dataclass
|
|
347
|
+
@PayloadRegistry.register
|
|
348
|
+
class ExtractFlowCommandsFromImageMetadataResultFailure(WorkflowNotAlteredMixin, ResultPayloadFailure):
|
|
349
|
+
"""Flow commands extraction failed.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
file_path: The file path that was attempted (for error context)
|
|
353
|
+
"""
|
|
354
|
+
|
|
355
|
+
file_path: str
|
|
356
|
+
|
|
357
|
+
|
|
291
358
|
@dataclass
|
|
292
359
|
@PayloadRegistry.register
|
|
293
360
|
class GetFlowDetailsRequest(RequestPayload):
|
|
@@ -607,7 +607,7 @@ class DiscoverLibrariesRequest(RequestPayload):
|
|
|
607
607
|
class DiscoverLibrariesResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
608
608
|
"""Libraries discovered successfully."""
|
|
609
609
|
|
|
610
|
-
libraries_discovered:
|
|
610
|
+
libraries_discovered: list[DiscoveredLibrary] # Discovered libraries in config order
|
|
611
611
|
|
|
612
612
|
|
|
613
613
|
@dataclass
|
|
@@ -54,6 +54,24 @@ class FileIOFailureReason(StrEnum):
|
|
|
54
54
|
IO_ERROR = "io_error" # Generic I/O error
|
|
55
55
|
UNKNOWN = "unknown" # Unexpected error
|
|
56
56
|
|
|
57
|
+
# Recycle bin errors
|
|
58
|
+
RECYCLE_BIN_UNAVAILABLE = "recycle_bin_unavailable" # Recycle bin unavailable and behavior was RECYCLE_BIN_ONLY
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class DeletionBehavior(StrEnum):
|
|
62
|
+
"""How to handle file/directory deletion."""
|
|
63
|
+
|
|
64
|
+
PERMANENTLY_DELETE = "permanently_delete" # Permanently delete (default, current behavior)
|
|
65
|
+
RECYCLE_BIN_ONLY = "recycle_bin_only" # Send to recycle bin; fail if unavailable
|
|
66
|
+
PREFER_RECYCLE_BIN = "prefer_recycle_bin" # Try recycle bin; fall back to permanent deletion
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class DeletionOutcome(StrEnum):
|
|
70
|
+
"""The actual outcome of a deletion operation."""
|
|
71
|
+
|
|
72
|
+
PERMANENTLY_DELETED = "permanently_deleted"
|
|
73
|
+
SENT_TO_RECYCLE_BIN = "sent_to_recycle_bin"
|
|
74
|
+
|
|
57
75
|
|
|
58
76
|
@dataclass
|
|
59
77
|
class FileSystemEntry:
|
|
@@ -585,6 +603,7 @@ class DeleteFileRequest(RequestPayload):
|
|
|
585
603
|
path: Path to file/directory to delete (mutually exclusive with file_entry)
|
|
586
604
|
file_entry: FileSystemEntry from directory listing (mutually exclusive with path)
|
|
587
605
|
workspace_only: If True, constrain to workspace directory
|
|
606
|
+
deletion_behavior: How to handle deletion (permanent, recycle bin only, or prefer recycle bin)
|
|
588
607
|
|
|
589
608
|
Results: DeleteFileResultSuccess | DeleteFileResultFailure
|
|
590
609
|
"""
|
|
@@ -592,6 +611,7 @@ class DeleteFileRequest(RequestPayload):
|
|
|
592
611
|
path: str | None = None
|
|
593
612
|
file_entry: FileSystemEntry | None = None
|
|
594
613
|
workspace_only: bool | None = True
|
|
614
|
+
deletion_behavior: DeletionBehavior = DeletionBehavior.PREFER_RECYCLE_BIN
|
|
595
615
|
|
|
596
616
|
|
|
597
617
|
@dataclass
|
|
@@ -603,11 +623,13 @@ class DeleteFileResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
|
603
623
|
deleted_path: The absolute path that was deleted (primary path)
|
|
604
624
|
was_directory: Whether the deleted item was a directory
|
|
605
625
|
deleted_paths: List of all paths that were deleted (for recursive deletes, includes all files/dirs)
|
|
626
|
+
outcome: The actual outcome of the deletion (permanently deleted or sent to recycle bin)
|
|
606
627
|
"""
|
|
607
628
|
|
|
608
629
|
deleted_path: str
|
|
609
630
|
was_directory: bool
|
|
610
631
|
deleted_paths: list[str]
|
|
632
|
+
outcome: DeletionOutcome
|
|
611
633
|
|
|
612
634
|
|
|
613
635
|
@dataclass
|
|
@@ -78,11 +78,13 @@ class CreateStaticFileUploadUrlResultSuccess(WorkflowNotAlteredMixin, ResultPayl
|
|
|
78
78
|
url: Presigned URL for uploading the file
|
|
79
79
|
headers: HTTP headers required for the upload request
|
|
80
80
|
method: HTTP method to use for upload (typically PUT)
|
|
81
|
+
file_url: File URI (file://) for the absolute path where the file will be accessible after upload
|
|
81
82
|
"""
|
|
82
83
|
|
|
83
84
|
url: str
|
|
84
85
|
headers: dict = field(default_factory=dict)
|
|
85
86
|
method: str = "PUT"
|
|
87
|
+
file_url: str = ""
|
|
86
88
|
|
|
87
89
|
|
|
88
90
|
@dataclass
|
|
@@ -100,13 +102,13 @@ class CreateStaticFileUploadUrlResultFailure(WorkflowNotAlteredMixin, ResultPayl
|
|
|
100
102
|
@dataclass
|
|
101
103
|
@PayloadRegistry.register
|
|
102
104
|
class CreateStaticFileDownloadUrlRequest(RequestPayload):
|
|
103
|
-
"""Create a presigned URL for downloading a static file via HTTP GET.
|
|
105
|
+
"""Create a presigned URL for downloading a static file from the staticfiles directory via HTTP GET.
|
|
104
106
|
|
|
105
|
-
Use when: Providing secure file access
|
|
106
|
-
enabling temporary download links, controlling file access permissions.
|
|
107
|
+
Use when: Providing secure file access to files in the staticfiles directory,
|
|
108
|
+
implementing file sharing, enabling temporary download links, controlling file access permissions.
|
|
107
109
|
|
|
108
110
|
Args:
|
|
109
|
-
file_name: Name of the file to be downloaded
|
|
111
|
+
file_name: Name of the file to be downloaded from the staticfiles directory
|
|
110
112
|
|
|
111
113
|
Results: CreateStaticFileDownloadUrlResultSuccess (with URL) | CreateStaticFileDownloadUrlResultFailure (URL creation error)
|
|
112
114
|
"""
|
|
@@ -114,6 +116,26 @@ class CreateStaticFileDownloadUrlRequest(RequestPayload):
|
|
|
114
116
|
file_name: str
|
|
115
117
|
|
|
116
118
|
|
|
119
|
+
@dataclass
|
|
120
|
+
@PayloadRegistry.register
|
|
121
|
+
class CreateStaticFileDownloadUrlFromPathRequest(RequestPayload):
|
|
122
|
+
"""Create a presigned URL for downloading a file from an arbitrary path.
|
|
123
|
+
|
|
124
|
+
Use when: Need to create download URLs for files outside the staticfiles directory,
|
|
125
|
+
working with absolute paths, file:// URLs, or workspace-relative paths.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
file_path: File path or URL. Accepts:
|
|
129
|
+
- file:// URLs (e.g., "file:///absolute/path/to/file.jpg")
|
|
130
|
+
- Absolute paths (e.g., "/absolute/path/to/file.jpg")
|
|
131
|
+
- Workspace-relative paths (e.g., "relative/path/to/file.jpg")
|
|
132
|
+
|
|
133
|
+
Results: CreateStaticFileDownloadUrlResultSuccess (with URL) | CreateStaticFileDownloadUrlResultFailure (URL creation error)
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
file_path: str
|
|
137
|
+
|
|
138
|
+
|
|
117
139
|
@dataclass
|
|
118
140
|
@PayloadRegistry.register
|
|
119
141
|
class CreateStaticFileDownloadUrlResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
@@ -121,9 +143,11 @@ class CreateStaticFileDownloadUrlResultSuccess(WorkflowNotAlteredMixin, ResultPa
|
|
|
121
143
|
|
|
122
144
|
Args:
|
|
123
145
|
url: Presigned URL for downloading the file
|
|
146
|
+
file_url: File URI (file://) for the absolute path to the file that was used to create the download URL
|
|
124
147
|
"""
|
|
125
148
|
|
|
126
149
|
url: str
|
|
150
|
+
file_url: str = ""
|
|
127
151
|
|
|
128
152
|
|
|
129
153
|
@dataclass
|