griptape-nodes 0.48.0__py3-none-any.whl → 0.50.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/__init__.py +12 -33
- griptape_nodes/app/app.py +6 -5
- griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +10 -2
- griptape_nodes/exe_types/core_types.py +8 -0
- griptape_nodes/exe_types/node_types.py +275 -1
- griptape_nodes/retained_mode/events/node_events.py +53 -0
- griptape_nodes/retained_mode/events/parameter_events.py +2 -0
- griptape_nodes/retained_mode/managers/flow_manager.py +26 -1
- griptape_nodes/retained_mode/managers/node_manager.py +202 -19
- griptape_nodes/utils/version_utils.py +75 -0
- {griptape_nodes-0.48.0.dist-info → griptape_nodes-0.50.0.dist-info}/METADATA +1 -1
- {griptape_nodes-0.48.0.dist-info → griptape_nodes-0.50.0.dist-info}/RECORD +14 -14
- {griptape_nodes-0.48.0.dist-info → griptape_nodes-0.50.0.dist-info}/WHEEL +1 -1
- {griptape_nodes-0.48.0.dist-info → griptape_nodes-0.50.0.dist-info}/entry_points.txt +0 -0
griptape_nodes/__init__.py
CHANGED
|
@@ -32,7 +32,13 @@ with console.status("Loading Griptape Nodes...") as status:
|
|
|
32
32
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
33
33
|
from griptape_nodes.retained_mode.managers.secrets_manager import SecretsManager
|
|
34
34
|
from griptape_nodes.utils.uv_utils import find_uv_bin
|
|
35
|
-
from griptape_nodes.utils.version_utils import
|
|
35
|
+
from griptape_nodes.utils.version_utils import (
|
|
36
|
+
get_complete_version_string,
|
|
37
|
+
get_current_version,
|
|
38
|
+
get_install_source,
|
|
39
|
+
get_latest_version_git,
|
|
40
|
+
get_latest_version_pypi,
|
|
41
|
+
)
|
|
36
42
|
|
|
37
43
|
CONFIG_DIR = xdg_config_home() / "griptape_nodes"
|
|
38
44
|
DATA_DIR = xdg_data_home() / "griptape_nodes"
|
|
@@ -642,38 +648,11 @@ def _get_latest_version(package: str, install_source: str) -> str:
|
|
|
642
648
|
str: Latest release tag (e.g., "v0.31.4")
|
|
643
649
|
"""
|
|
644
650
|
if install_source == "pypi":
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
response.raise_for_status()
|
|
651
|
-
data = response.json()
|
|
652
|
-
return f"v{data['info']['version']}"
|
|
653
|
-
except httpx.HTTPStatusError as e:
|
|
654
|
-
console.print(f"[red]Error fetching latest version: {e}[/red]")
|
|
655
|
-
return get_current_version()
|
|
656
|
-
elif install_source == "git":
|
|
657
|
-
# We only install auto updating from the 'latest' tag
|
|
658
|
-
revision = LATEST_TAG
|
|
659
|
-
update_url = GITHUB_UPDATE_URL.format(package=package, revision=revision)
|
|
660
|
-
|
|
661
|
-
with httpx.Client() as client:
|
|
662
|
-
response = client.get(update_url)
|
|
663
|
-
try:
|
|
664
|
-
response.raise_for_status()
|
|
665
|
-
# Get the latest commit SHA for the tag, this effectively the latest version of the package
|
|
666
|
-
data = response.json()
|
|
667
|
-
if "object" in data and "sha" in data["object"]:
|
|
668
|
-
return data["object"]["sha"][:7]
|
|
669
|
-
# Should not happen, but if it does, return the current version
|
|
670
|
-
return get_current_version()
|
|
671
|
-
except httpx.HTTPStatusError as e:
|
|
672
|
-
console.print(f"[red]Error fetching latest version: {e}[/red]")
|
|
673
|
-
return get_current_version()
|
|
674
|
-
else:
|
|
675
|
-
# If the package is installed from a file, just return the current version since the user is likely managing it manually
|
|
676
|
-
return get_current_version()
|
|
651
|
+
return get_latest_version_pypi(package, PYPI_UPDATE_URL)
|
|
652
|
+
if install_source == "git":
|
|
653
|
+
return get_latest_version_git(package, GITHUB_UPDATE_URL, LATEST_TAG)
|
|
654
|
+
# If the package is installed from a file, just return the current version since the user is likely managing it manually
|
|
655
|
+
return get_current_version()
|
|
677
656
|
|
|
678
657
|
|
|
679
658
|
def _auto_update_self() -> None:
|
griptape_nodes/app/app.py
CHANGED
|
@@ -92,7 +92,6 @@ def start_app() -> None:
|
|
|
92
92
|
Starts the event loop and listens for events from the Nodes API.
|
|
93
93
|
"""
|
|
94
94
|
_init_event_listeners()
|
|
95
|
-
|
|
96
95
|
# Listen for any signals to exit the app
|
|
97
96
|
for sig in (signal.SIGINT, signal.SIGTERM):
|
|
98
97
|
signal.signal(sig, lambda *_: sys.exit(0))
|
|
@@ -100,11 +99,9 @@ def start_app() -> None:
|
|
|
100
99
|
api_key = _ensure_api_key()
|
|
101
100
|
threading.Thread(target=mcp_server, args=(api_key,), daemon=True).start()
|
|
102
101
|
threading.Thread(target=_listen_for_api_events, args=(api_key,), daemon=True).start()
|
|
103
|
-
|
|
104
102
|
if STATIC_SERVER_ENABLED:
|
|
105
103
|
static_dir = _build_static_dir()
|
|
106
104
|
threading.Thread(target=start_api, args=(static_dir, event_queue), daemon=True).start()
|
|
107
|
-
|
|
108
105
|
_process_event_queue()
|
|
109
106
|
|
|
110
107
|
|
|
@@ -263,8 +260,12 @@ def _process_event_queue() -> None:
|
|
|
263
260
|
Event queue will be populated by background threads listening for events from the Nodes API.
|
|
264
261
|
"""
|
|
265
262
|
# Wait for WebSocket connection to be established before processing events
|
|
266
|
-
ws_ready_event.wait()
|
|
267
|
-
|
|
263
|
+
timed_out = ws_ready_event.wait(timeout=15)
|
|
264
|
+
if not timed_out:
|
|
265
|
+
console.print(
|
|
266
|
+
"[red] The connection to the websocket timed out. Please check your internet connection or the status of Griptape Nodes API.[/red]"
|
|
267
|
+
)
|
|
268
|
+
sys.exit(1)
|
|
268
269
|
while True:
|
|
269
270
|
event = event_queue.get(block=True)
|
|
270
271
|
if isinstance(event, EventRequest):
|
|
@@ -92,7 +92,7 @@ class LocalWorkflowExecutor(WorkflowExecutor):
|
|
|
92
92
|
node_name = result_event.payload.node_name
|
|
93
93
|
flow_name = GriptapeNodes.NodeManager().get_node_parent_flow_by_name(node_name)
|
|
94
94
|
event_request = EventRequest(request=SingleExecutionStepRequest(flow_name=flow_name))
|
|
95
|
-
|
|
95
|
+
self.queue.put(event_request)
|
|
96
96
|
|
|
97
97
|
elif type(result_event.payload).__name__ == "NodeFinishProcessEvent":
|
|
98
98
|
event_log = f"NodeFinishProcessEvent: {result_event.payload}"
|
|
@@ -196,7 +196,13 @@ class LocalWorkflowExecutor(WorkflowExecutor):
|
|
|
196
196
|
try:
|
|
197
197
|
event = self.queue.get(block=True)
|
|
198
198
|
|
|
199
|
-
if isinstance(event,
|
|
199
|
+
if isinstance(event, EventRequest):
|
|
200
|
+
# Handle EventRequest objects by processing them through GriptapeNodes
|
|
201
|
+
request_payload = event.request
|
|
202
|
+
GriptapeNodes.handle_request(
|
|
203
|
+
request_payload, response_topic=event.response_topic, request_id=event.request_id
|
|
204
|
+
)
|
|
205
|
+
elif isinstance(event, ExecutionGriptapeNodeEvent):
|
|
200
206
|
result_event = event.wrapped_event
|
|
201
207
|
|
|
202
208
|
if type(result_event.payload).__name__ == "ControlFlowResolvedEvent":
|
|
@@ -208,6 +214,8 @@ class LocalWorkflowExecutor(WorkflowExecutor):
|
|
|
208
214
|
is_flow_finished = True
|
|
209
215
|
logger.error(msg)
|
|
210
216
|
error = LocalExecutorError(msg)
|
|
217
|
+
else:
|
|
218
|
+
logger.info("Unknown event type encountered: %s", type(event))
|
|
211
219
|
|
|
212
220
|
self.queue.task_done()
|
|
213
221
|
|
|
@@ -714,6 +714,10 @@ class Parameter(BaseNodeElement, UIOptionsMixin):
|
|
|
714
714
|
# During save/load, this value IS still serialized to save its proper state.
|
|
715
715
|
settable: bool = True
|
|
716
716
|
|
|
717
|
+
# "serializable" controls whether parameter values should be serialized during save/load operations.
|
|
718
|
+
# Set to False for parameters containing non-serializable types (ImageDrivers, PromptDrivers, file handles, etc.)
|
|
719
|
+
serializable: bool = True
|
|
720
|
+
|
|
717
721
|
user_defined: bool = False
|
|
718
722
|
_allowed_modes: set = field(
|
|
719
723
|
default_factory=lambda: {
|
|
@@ -747,6 +751,7 @@ class Parameter(BaseNodeElement, UIOptionsMixin):
|
|
|
747
751
|
ui_options: dict | None = None,
|
|
748
752
|
*,
|
|
749
753
|
settable: bool = True,
|
|
754
|
+
serializable: bool = True,
|
|
750
755
|
user_defined: bool = False,
|
|
751
756
|
element_id: str | None = None,
|
|
752
757
|
element_type: str | None = None,
|
|
@@ -764,6 +769,7 @@ class Parameter(BaseNodeElement, UIOptionsMixin):
|
|
|
764
769
|
self.tooltip_as_property = tooltip_as_property
|
|
765
770
|
self.tooltip_as_output = tooltip_as_output
|
|
766
771
|
self.settable = settable
|
|
772
|
+
self.serializable = serializable
|
|
767
773
|
self.user_defined = user_defined
|
|
768
774
|
if allowed_modes is None:
|
|
769
775
|
self._allowed_modes = {ParameterMode.INPUT, ParameterMode.OUTPUT, ParameterMode.PROPERTY}
|
|
@@ -813,6 +819,8 @@ class Parameter(BaseNodeElement, UIOptionsMixin):
|
|
|
813
819
|
our_dict["tooltip_as_property"] = self.tooltip_as_property
|
|
814
820
|
|
|
815
821
|
our_dict["is_user_defined"] = self.user_defined
|
|
822
|
+
our_dict["settable"] = self.settable
|
|
823
|
+
our_dict["serializable"] = self.serializable
|
|
816
824
|
our_dict["ui_options"] = self.ui_options
|
|
817
825
|
|
|
818
826
|
# Let's bundle up the mode details.
|
|
@@ -4,7 +4,7 @@ import logging
|
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
5
|
from collections.abc import Callable, Generator, Iterable
|
|
6
6
|
from enum import StrEnum, auto
|
|
7
|
-
from typing import Any, TypeVar
|
|
7
|
+
from typing import Any, NamedTuple, TypeVar
|
|
8
8
|
|
|
9
9
|
from griptape.events import BaseEvent, EventBus
|
|
10
10
|
|
|
@@ -26,12 +26,14 @@ from griptape_nodes.retained_mode.events.base_events import (
|
|
|
26
26
|
ExecutionEvent,
|
|
27
27
|
ExecutionGriptapeNodeEvent,
|
|
28
28
|
ProgressEvent,
|
|
29
|
+
RequestPayload,
|
|
29
30
|
)
|
|
30
31
|
from griptape_nodes.retained_mode.events.execution_events import (
|
|
31
32
|
NodeUnresolvedEvent,
|
|
32
33
|
ParameterValueUpdateEvent,
|
|
33
34
|
)
|
|
34
35
|
from griptape_nodes.retained_mode.events.parameter_events import (
|
|
36
|
+
AddParameterToNodeRequest,
|
|
35
37
|
RemoveElementEvent,
|
|
36
38
|
RemoveParameterFromNodeRequest,
|
|
37
39
|
)
|
|
@@ -52,6 +54,23 @@ class NodeResolutionState(StrEnum):
|
|
|
52
54
|
RESOLVED = auto()
|
|
53
55
|
|
|
54
56
|
|
|
57
|
+
class NodeMessageResult(NamedTuple):
|
|
58
|
+
"""Result from a node message callback.
|
|
59
|
+
|
|
60
|
+
Attributes:
|
|
61
|
+
success: True if the message was handled successfully, False otherwise
|
|
62
|
+
details: Human-readable description of what happened
|
|
63
|
+
response: Optional response data to return to the sender
|
|
64
|
+
altered_workflow_state: True if the message handling altered workflow state.
|
|
65
|
+
Clients can use this to determine if the workflow needs to be re-saved.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
success: bool
|
|
69
|
+
details: str
|
|
70
|
+
response: Any = None
|
|
71
|
+
altered_workflow_state: bool = True
|
|
72
|
+
|
|
73
|
+
|
|
55
74
|
class BaseNode(ABC):
|
|
56
75
|
# Owned by a flow
|
|
57
76
|
name: str
|
|
@@ -148,6 +167,15 @@ class BaseNode(ABC):
|
|
|
148
167
|
"""Callback to confirm allowing a Connection going OUT of this Node."""
|
|
149
168
|
return True
|
|
150
169
|
|
|
170
|
+
def before_incoming_connection(
|
|
171
|
+
self,
|
|
172
|
+
source_node: BaseNode, # noqa: ARG002
|
|
173
|
+
source_parameter_name: str, # noqa: ARG002
|
|
174
|
+
target_parameter_name: str, # noqa: ARG002
|
|
175
|
+
) -> None:
|
|
176
|
+
"""Callback before validating a Connection coming TO this Node."""
|
|
177
|
+
return
|
|
178
|
+
|
|
151
179
|
def after_incoming_connection(
|
|
152
180
|
self,
|
|
153
181
|
source_node: BaseNode, # noqa: ARG002
|
|
@@ -157,6 +185,15 @@ class BaseNode(ABC):
|
|
|
157
185
|
"""Callback after a Connection has been established TO this Node."""
|
|
158
186
|
return
|
|
159
187
|
|
|
188
|
+
def before_outgoing_connection(
|
|
189
|
+
self,
|
|
190
|
+
source_parameter_name: str, # noqa: ARG002
|
|
191
|
+
target_node: BaseNode, # noqa: ARG002
|
|
192
|
+
target_parameter_name: str, # noqa: ARG002
|
|
193
|
+
) -> None:
|
|
194
|
+
"""Callback before validating a Connection going OUT of this Node."""
|
|
195
|
+
return
|
|
196
|
+
|
|
160
197
|
def after_outgoing_connection(
|
|
161
198
|
self,
|
|
162
199
|
source_parameter: Parameter, # noqa: ARG002
|
|
@@ -251,6 +288,31 @@ class BaseNode(ABC):
|
|
|
251
288
|
"""Callback for when a Griptape Event comes destined for this Node."""
|
|
252
289
|
return
|
|
253
290
|
|
|
291
|
+
def on_node_message_received(
|
|
292
|
+
self,
|
|
293
|
+
optional_element_name: str | None, # noqa: ARG002
|
|
294
|
+
message_type: str,
|
|
295
|
+
message: Any, # noqa: ARG002
|
|
296
|
+
) -> NodeMessageResult:
|
|
297
|
+
"""Callback for when a message is sent directly to this node.
|
|
298
|
+
|
|
299
|
+
Custom nodes may elect to override this method to handle specific message types
|
|
300
|
+
and implement custom communication patterns with external systems.
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
optional_element_name: Optional element name this message relates to
|
|
304
|
+
message_type: String indicating the message type for parsing
|
|
305
|
+
message: Message payload of any type
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
NodeMessageResult: Result containing success status, details, and optional response
|
|
309
|
+
"""
|
|
310
|
+
return NodeMessageResult(
|
|
311
|
+
success=False,
|
|
312
|
+
details=f"Node '{self.name}' was sent a message of type '{message_type}'. Failed because no message handler was specified for this node. Implement the on_node_message_received method in this node class in order for it to receive messages.",
|
|
313
|
+
response=None,
|
|
314
|
+
)
|
|
315
|
+
|
|
254
316
|
def does_name_exist(self, param_name: str) -> bool:
|
|
255
317
|
for parameter in self.parameters:
|
|
256
318
|
if parameter.name == param_name:
|
|
@@ -1070,6 +1132,218 @@ class EndLoopNode(BaseNode):
|
|
|
1070
1132
|
"""Creating class for Start Loop Node in order to implement loop functionality in execution."""
|
|
1071
1133
|
|
|
1072
1134
|
|
|
1135
|
+
class ErrorProxyNode(BaseNode):
|
|
1136
|
+
"""A proxy node that substitutes for nodes that failed to create due to missing dependencies or errors.
|
|
1137
|
+
|
|
1138
|
+
This node maintains the original node type information and allows workflows to continue loading
|
|
1139
|
+
even when some node types are unavailable. It generates parameters dynamically as connections
|
|
1140
|
+
and values are assigned to maintain workflow structure.
|
|
1141
|
+
"""
|
|
1142
|
+
|
|
1143
|
+
def __init__(
|
|
1144
|
+
self,
|
|
1145
|
+
name: str,
|
|
1146
|
+
original_node_type: str,
|
|
1147
|
+
original_library_name: str,
|
|
1148
|
+
failure_reason: str,
|
|
1149
|
+
metadata: dict[Any, Any] | None = None,
|
|
1150
|
+
) -> None:
|
|
1151
|
+
super().__init__(name, metadata)
|
|
1152
|
+
|
|
1153
|
+
self.original_node_type = original_node_type
|
|
1154
|
+
self.original_library_name = original_library_name
|
|
1155
|
+
self.failure_reason = failure_reason
|
|
1156
|
+
# Record ALL initial_setup=True requests in order for 1:1 replay
|
|
1157
|
+
self._recorded_initialization_requests: list[RequestPayload] = []
|
|
1158
|
+
|
|
1159
|
+
# Track if user has made connection modifications after initial setup
|
|
1160
|
+
self._has_connection_modifications: bool = False
|
|
1161
|
+
|
|
1162
|
+
# Add error message parameter explaining the failure
|
|
1163
|
+
self._error_message = ParameterMessage(
|
|
1164
|
+
name="error_proxy_message",
|
|
1165
|
+
variant="error",
|
|
1166
|
+
value="", # Will be set by _update_error_message
|
|
1167
|
+
)
|
|
1168
|
+
self.add_node_element(self._error_message)
|
|
1169
|
+
self._update_error_message()
|
|
1170
|
+
|
|
1171
|
+
def _get_base_error_message(self) -> str:
|
|
1172
|
+
"""Generate the base error message for this ErrorProxyNode."""
|
|
1173
|
+
return (
|
|
1174
|
+
f"This is a placeholder for a node of type '{self.original_node_type}'"
|
|
1175
|
+
f"\nfrom the '{self.original_library_name}' library."
|
|
1176
|
+
f"\nIt encountered a problem when loading."
|
|
1177
|
+
f"\nThe technical issue:\n{self.failure_reason}\n\n"
|
|
1178
|
+
f"Your original node will be restored once the issue above is fixed"
|
|
1179
|
+
f"(which may require registering the appropriate library, or getting"
|
|
1180
|
+
f"a code fix from the node author)."
|
|
1181
|
+
)
|
|
1182
|
+
|
|
1183
|
+
def on_attempt_set_parameter_value(self, param_name: str) -> None:
|
|
1184
|
+
"""Public method to attempt setting a parameter value during initial setup.
|
|
1185
|
+
|
|
1186
|
+
Creates a PROPERTY mode parameter if it doesn't exist to support value setting.
|
|
1187
|
+
|
|
1188
|
+
Args:
|
|
1189
|
+
param_name: Name of the parameter to prepare for value setting
|
|
1190
|
+
"""
|
|
1191
|
+
self._ensure_parameter_exists(param_name)
|
|
1192
|
+
|
|
1193
|
+
def _ensure_parameter_exists(self, param_name: str) -> None:
|
|
1194
|
+
"""Ensures a parameter exists on this node.
|
|
1195
|
+
|
|
1196
|
+
Creates a universal parameter with all modes enabled for maximum flexibility.
|
|
1197
|
+
Auto-generated parameters are marked as non-user-defined so they don't get serialized.
|
|
1198
|
+
|
|
1199
|
+
Args:
|
|
1200
|
+
param_name: Name of the parameter to ensure exists
|
|
1201
|
+
"""
|
|
1202
|
+
existing_param = super().get_parameter_by_name(param_name)
|
|
1203
|
+
|
|
1204
|
+
if existing_param is None:
|
|
1205
|
+
# Create new universal parameter with all modes enabled
|
|
1206
|
+
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
1207
|
+
|
|
1208
|
+
request = AddParameterToNodeRequest(
|
|
1209
|
+
node_name=self.name,
|
|
1210
|
+
parameter_name=param_name,
|
|
1211
|
+
type=ParameterTypeBuiltin.ANY.value, # ANY = parameter's main type for maximum flexibility
|
|
1212
|
+
input_types=[ParameterTypeBuiltin.ANY.value], # ANY = accepts any single input type
|
|
1213
|
+
output_type=ParameterTypeBuiltin.ALL.value, # ALL = can output any type (passthrough)
|
|
1214
|
+
tooltip="Parameter created for placeholder node to preserve workflow connections",
|
|
1215
|
+
mode_allowed_input=True, # Enable all modes upfront
|
|
1216
|
+
mode_allowed_output=True,
|
|
1217
|
+
mode_allowed_property=True,
|
|
1218
|
+
is_user_defined=False, # Don't serialize this parameter
|
|
1219
|
+
initial_setup=True, # Allows setting non-settable parameters and prevents resolution cascades during workflow loading
|
|
1220
|
+
)
|
|
1221
|
+
result = GriptapeNodes.handle_request(request)
|
|
1222
|
+
|
|
1223
|
+
# Check if parameter creation was successful
|
|
1224
|
+
from griptape_nodes.retained_mode.events.parameter_events import AddParameterToNodeResultSuccess
|
|
1225
|
+
|
|
1226
|
+
if not isinstance(result, AddParameterToNodeResultSuccess):
|
|
1227
|
+
failure_message = f"Failed to create parameter '{param_name}': {result.result_details}"
|
|
1228
|
+
raise RuntimeError(failure_message)
|
|
1229
|
+
# If parameter already exists, nothing to do - it already has all modes
|
|
1230
|
+
|
|
1231
|
+
def allow_incoming_connection(
|
|
1232
|
+
self,
|
|
1233
|
+
source_node: BaseNode, # noqa: ARG002
|
|
1234
|
+
source_parameter: Parameter, # noqa: ARG002
|
|
1235
|
+
target_parameter: Parameter, # noqa: ARG002
|
|
1236
|
+
) -> bool:
|
|
1237
|
+
"""ErrorProxyNode allows connections - it's a shell for maintaining connections."""
|
|
1238
|
+
return True
|
|
1239
|
+
|
|
1240
|
+
def allow_outgoing_connection(
|
|
1241
|
+
self,
|
|
1242
|
+
source_parameter: Parameter, # noqa: ARG002
|
|
1243
|
+
target_node: BaseNode, # noqa: ARG002
|
|
1244
|
+
target_parameter: Parameter, # noqa: ARG002
|
|
1245
|
+
) -> bool:
|
|
1246
|
+
"""ErrorProxyNode allows connections - it's a shell for maintaining connections."""
|
|
1247
|
+
return True
|
|
1248
|
+
|
|
1249
|
+
def before_incoming_connection(
|
|
1250
|
+
self,
|
|
1251
|
+
source_node: BaseNode, # noqa: ARG002
|
|
1252
|
+
source_parameter_name: str, # noqa: ARG002
|
|
1253
|
+
target_parameter_name: str,
|
|
1254
|
+
) -> None:
|
|
1255
|
+
"""Create target parameter before connection validation."""
|
|
1256
|
+
self._ensure_parameter_exists(target_parameter_name)
|
|
1257
|
+
|
|
1258
|
+
def before_outgoing_connection(
|
|
1259
|
+
self,
|
|
1260
|
+
source_parameter_name: str,
|
|
1261
|
+
target_node: BaseNode, # noqa: ARG002
|
|
1262
|
+
target_parameter_name: str, # noqa: ARG002
|
|
1263
|
+
) -> None:
|
|
1264
|
+
"""Create source parameter before connection validation."""
|
|
1265
|
+
self._ensure_parameter_exists(source_parameter_name)
|
|
1266
|
+
|
|
1267
|
+
def set_post_init_connections_modified(self) -> None:
|
|
1268
|
+
"""Mark that user-initiated connections have been modified and update the warning message."""
|
|
1269
|
+
if not self._has_connection_modifications:
|
|
1270
|
+
self._has_connection_modifications = True
|
|
1271
|
+
self._update_error_message()
|
|
1272
|
+
|
|
1273
|
+
def _update_error_message(self) -> None:
|
|
1274
|
+
"""Update the ParameterMessage to include connection modification warning."""
|
|
1275
|
+
# Build the updated message with connection warning
|
|
1276
|
+
base_message = self._get_base_error_message()
|
|
1277
|
+
|
|
1278
|
+
# Add connection modification warning if applicable
|
|
1279
|
+
if self._has_connection_modifications:
|
|
1280
|
+
connection_warning = (
|
|
1281
|
+
"\n\nWARNING: You have modified connections to this placeholder node."
|
|
1282
|
+
"\nThis may require manual fixes when the original node is restored."
|
|
1283
|
+
)
|
|
1284
|
+
final_message = base_message + connection_warning
|
|
1285
|
+
else:
|
|
1286
|
+
# Add the general note only if no modifications have been made
|
|
1287
|
+
general_warning = (
|
|
1288
|
+
"\n\nNote: Making changes to this node may require manual fixes when restored,"
|
|
1289
|
+
"\nas we can't predict how all node authors craft their custom nodes."
|
|
1290
|
+
)
|
|
1291
|
+
final_message = base_message + general_warning
|
|
1292
|
+
|
|
1293
|
+
# Update the error message value
|
|
1294
|
+
self._error_message.value = final_message
|
|
1295
|
+
|
|
1296
|
+
def validate_before_node_run(self) -> list[Exception] | None:
|
|
1297
|
+
"""Prevent ErrorProxy nodes from running - validate at node level only."""
|
|
1298
|
+
error_msg = (
|
|
1299
|
+
f"Cannot run node '{self.name}': This is a placeholder node put in place to preserve your workflow until the breaking issue is fixed.\n\n"
|
|
1300
|
+
f"The original '{self.original_node_type}' from library '{self.original_library_name}' failed to load due to this technical issue:\n\n"
|
|
1301
|
+
f"{self.failure_reason}\n\n"
|
|
1302
|
+
f"Once you resolve the issue above, reload this workflow and the placeholder will be automatically replaced with the original node."
|
|
1303
|
+
)
|
|
1304
|
+
return [RuntimeError(error_msg)]
|
|
1305
|
+
|
|
1306
|
+
def record_initialization_request(self, request: RequestPayload) -> None:
|
|
1307
|
+
"""Record an initialization request for replay during serialization.
|
|
1308
|
+
|
|
1309
|
+
This method captures requests that modify ErrorProxyNode structure during workflow loading,
|
|
1310
|
+
preserving information needed for restoration when the original node becomes available.
|
|
1311
|
+
|
|
1312
|
+
WHAT WE RECORD:
|
|
1313
|
+
- AlterParameterDetailsRequest: Parameter modifications from original node definition
|
|
1314
|
+
- Any request with initial_setup=True that changes node structure in ways that cannot
|
|
1315
|
+
be reconstructed from final state alone
|
|
1316
|
+
|
|
1317
|
+
WHAT WE DO NOT RECORD (and why):
|
|
1318
|
+
- SetParameterValueRequest: Final parameter values are serialized normally via parameter_values
|
|
1319
|
+
- AddParameterToNodeRequest: User-defined parameters are serialized via is_user_defined=True flag
|
|
1320
|
+
- CreateConnectionRequest: Connections are serialized separately and recreated during loading
|
|
1321
|
+
- RenameParameterRequest: Final parameter names are preserved in serialized state
|
|
1322
|
+
- SetNodeMetadataRequest: Final metadata state is preserved in node.metadata
|
|
1323
|
+
- SetLockNodeStateRequest: Final lock state is preserved in node.lock
|
|
1324
|
+
"""
|
|
1325
|
+
self._recorded_initialization_requests.append(request)
|
|
1326
|
+
|
|
1327
|
+
def get_recorded_initialization_requests(self, request_type: type | None = None) -> list[RequestPayload]:
|
|
1328
|
+
"""Get recorded initialization requests for 1:1 serialization replay.
|
|
1329
|
+
|
|
1330
|
+
Args:
|
|
1331
|
+
request_type: Optional class to filter by. If provided, only returns requests
|
|
1332
|
+
of that type. If None, returns all recorded requests.
|
|
1333
|
+
|
|
1334
|
+
Returns:
|
|
1335
|
+
List of recorded requests in the order they were received.
|
|
1336
|
+
"""
|
|
1337
|
+
if request_type is None:
|
|
1338
|
+
return self._recorded_initialization_requests
|
|
1339
|
+
|
|
1340
|
+
return [req for req in self._recorded_initialization_requests if isinstance(req, request_type)]
|
|
1341
|
+
|
|
1342
|
+
def process(self) -> Any:
|
|
1343
|
+
"""No-op process method. Error Proxy nodes do nothing during execution."""
|
|
1344
|
+
return None
|
|
1345
|
+
|
|
1346
|
+
|
|
1073
1347
|
class Connection:
|
|
1074
1348
|
source_node: BaseNode
|
|
1075
1349
|
target_node: BaseNode
|
|
@@ -45,6 +45,7 @@ class CreateNodeRequest(RequestPayload):
|
|
|
45
45
|
resolution: Initial resolution state (defaults to UNRESOLVED)
|
|
46
46
|
initial_setup: Skip setup work when loading from file (defaults to False)
|
|
47
47
|
set_as_new_context: Set this node as current context after creation (defaults to False)
|
|
48
|
+
create_error_proxy_on_failure: Create Error Proxy node if creation fails (defaults to True)
|
|
48
49
|
|
|
49
50
|
Results: CreateNodeResultSuccess (with assigned name) | CreateNodeResultFailure (invalid type, missing library, flow not found)
|
|
50
51
|
"""
|
|
@@ -60,6 +61,8 @@ class CreateNodeRequest(RequestPayload):
|
|
|
60
61
|
initial_setup: bool = False
|
|
61
62
|
# When True, this Node will be pushed as the current Node within the Current Context.
|
|
62
63
|
set_as_new_context: bool = False
|
|
64
|
+
# When True, create an Error Proxy node if the requested node type fails to create
|
|
65
|
+
create_error_proxy_on_failure: bool = True
|
|
63
66
|
|
|
64
67
|
|
|
65
68
|
@dataclass
|
|
@@ -677,3 +680,53 @@ class DuplicateSelectedNodesResultFailure(WorkflowNotAlteredMixin, ResultPayload
|
|
|
677
680
|
Common causes: nodes not found, constraints/conflicts,
|
|
678
681
|
insufficient resources, connection duplication failures.
|
|
679
682
|
"""
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
@dataclass
|
|
686
|
+
@PayloadRegistry.register
|
|
687
|
+
class SendNodeMessageRequest(RequestPayload):
|
|
688
|
+
"""Send a message to a specific node.
|
|
689
|
+
|
|
690
|
+
Use when: External systems need to signal or send data directly to individual nodes,
|
|
691
|
+
implementing custom communication patterns, triggering node-specific behaviors.
|
|
692
|
+
|
|
693
|
+
Args:
|
|
694
|
+
node_name: Name of the target node (None for current context node)
|
|
695
|
+
optional_element_name: Optional element name this message relates to
|
|
696
|
+
message_type: String indicating message type for receiver parsing
|
|
697
|
+
message: Message payload of any type
|
|
698
|
+
|
|
699
|
+
Results: SendNodeMessageResultSuccess (with response) | SendNodeMessageResultFailure (node not found, handler error)
|
|
700
|
+
"""
|
|
701
|
+
|
|
702
|
+
message_type: str
|
|
703
|
+
message: Any
|
|
704
|
+
node_name: str | None = None
|
|
705
|
+
optional_element_name: str | None = None
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
@dataclass
|
|
709
|
+
@PayloadRegistry.register
|
|
710
|
+
class SendNodeMessageResultSuccess(ResultPayloadSuccess):
|
|
711
|
+
"""Node message sent and processed successfully.
|
|
712
|
+
|
|
713
|
+
Args:
|
|
714
|
+
response: Optional response data from the node's message handler
|
|
715
|
+
"""
|
|
716
|
+
|
|
717
|
+
response: Any = None
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
@dataclass
|
|
721
|
+
@PayloadRegistry.register
|
|
722
|
+
class SendNodeMessageResultFailure(ResultPayloadFailure):
|
|
723
|
+
"""Node message sending failed.
|
|
724
|
+
|
|
725
|
+
Common causes: node not found, no current context, message handler error,
|
|
726
|
+
unsupported message type.
|
|
727
|
+
|
|
728
|
+
Args:
|
|
729
|
+
response: Optional response data from the node's message handler (even on failure)
|
|
730
|
+
"""
|
|
731
|
+
|
|
732
|
+
response: Any = None
|
|
@@ -40,6 +40,7 @@ class AddParameterToNodeRequest(RequestPayload):
|
|
|
40
40
|
mode_allowed_input: Whether parameter can be used as input
|
|
41
41
|
mode_allowed_property: Whether parameter can be used as property
|
|
42
42
|
mode_allowed_output: Whether parameter can be used as output
|
|
43
|
+
is_user_defined: Whether this is a user-defined parameter (affects serialization)
|
|
43
44
|
parent_container_name: Name of parent container if nested
|
|
44
45
|
initial_setup: Skip setup work when loading from file
|
|
45
46
|
|
|
@@ -61,6 +62,7 @@ class AddParameterToNodeRequest(RequestPayload):
|
|
|
61
62
|
mode_allowed_input: bool = Field(default=True)
|
|
62
63
|
mode_allowed_property: bool = Field(default=True)
|
|
63
64
|
mode_allowed_output: bool = Field(default=True)
|
|
65
|
+
is_user_defined: bool = Field(default=True)
|
|
64
66
|
parent_container_name: str | None = None
|
|
65
67
|
# initial_setup prevents unnecessary work when we are loading a workflow from a file.
|
|
66
68
|
initial_setup: bool = False
|
|
@@ -14,7 +14,7 @@ from griptape_nodes.exe_types.core_types import (
|
|
|
14
14
|
ParameterTypeBuiltin,
|
|
15
15
|
)
|
|
16
16
|
from griptape_nodes.exe_types.flow import ControlFlow
|
|
17
|
-
from griptape_nodes.exe_types.node_types import BaseNode, NodeResolutionState, StartLoopNode, StartNode
|
|
17
|
+
from griptape_nodes.exe_types.node_types import BaseNode, ErrorProxyNode, NodeResolutionState, StartLoopNode, StartNode
|
|
18
18
|
from griptape_nodes.machines.control_flow import CompleteState, ControlFlowMachine
|
|
19
19
|
from griptape_nodes.retained_mode.events.base_events import (
|
|
20
20
|
ExecutionEvent,
|
|
@@ -681,6 +681,18 @@ class FlowManager:
|
|
|
681
681
|
|
|
682
682
|
# Cross-flow connections are now supported via global connection storage
|
|
683
683
|
|
|
684
|
+
# Call before_connection callbacks to allow nodes to prepare parameters
|
|
685
|
+
source_node.before_outgoing_connection(
|
|
686
|
+
source_parameter_name=request.source_parameter_name,
|
|
687
|
+
target_node=target_node,
|
|
688
|
+
target_parameter_name=request.target_parameter_name,
|
|
689
|
+
)
|
|
690
|
+
target_node.before_incoming_connection(
|
|
691
|
+
source_node=source_node,
|
|
692
|
+
source_parameter_name=request.source_parameter_name,
|
|
693
|
+
target_parameter_name=request.target_parameter_name,
|
|
694
|
+
)
|
|
695
|
+
|
|
684
696
|
# Now validate the parameters.
|
|
685
697
|
source_param = source_node.get_parameter_by_name(request.source_parameter_name)
|
|
686
698
|
if source_param is None:
|
|
@@ -852,6 +864,13 @@ class FlowManager:
|
|
|
852
864
|
)
|
|
853
865
|
)
|
|
854
866
|
|
|
867
|
+
# Check if either node is ErrorProxyNode and mark connection modification if not initial_setup
|
|
868
|
+
if not request.initial_setup:
|
|
869
|
+
if isinstance(source_node, ErrorProxyNode):
|
|
870
|
+
source_node.set_post_init_connections_modified()
|
|
871
|
+
if isinstance(target_node, ErrorProxyNode):
|
|
872
|
+
target_node.set_post_init_connections_modified()
|
|
873
|
+
|
|
855
874
|
result = CreateConnectionResultSuccess()
|
|
856
875
|
|
|
857
876
|
return result
|
|
@@ -995,6 +1014,12 @@ class FlowManager:
|
|
|
995
1014
|
details = f'Connection "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}" deleted.'
|
|
996
1015
|
logger.debug(details)
|
|
997
1016
|
|
|
1017
|
+
# Check if either node is ErrorProxyNode and mark connection modification (deletes are always user-initiated)
|
|
1018
|
+
if isinstance(source_node, ErrorProxyNode):
|
|
1019
|
+
source_node.set_post_init_connections_modified()
|
|
1020
|
+
if isinstance(target_node, ErrorProxyNode):
|
|
1021
|
+
target_node.set_post_init_connections_modified()
|
|
1022
|
+
|
|
998
1023
|
result = DeleteConnectionResultSuccess()
|
|
999
1024
|
return result
|
|
1000
1025
|
|
|
@@ -13,10 +13,17 @@ from griptape_nodes.exe_types.core_types import (
|
|
|
13
13
|
ParameterTypeBuiltin,
|
|
14
14
|
)
|
|
15
15
|
from griptape_nodes.exe_types.flow import ControlFlow
|
|
16
|
-
from griptape_nodes.exe_types.node_types import
|
|
16
|
+
from griptape_nodes.exe_types.node_types import (
|
|
17
|
+
BaseNode,
|
|
18
|
+
EndLoopNode,
|
|
19
|
+
ErrorProxyNode,
|
|
20
|
+
NodeResolutionState,
|
|
21
|
+
StartLoopNode,
|
|
22
|
+
)
|
|
17
23
|
from griptape_nodes.exe_types.type_validator import TypeValidator
|
|
18
24
|
from griptape_nodes.node_library.library_registry import LibraryNameAndVersion, LibraryRegistry
|
|
19
25
|
from griptape_nodes.retained_mode.events.base_events import (
|
|
26
|
+
ResultDetails,
|
|
20
27
|
ResultPayload,
|
|
21
28
|
ResultPayloadFailure,
|
|
22
29
|
)
|
|
@@ -73,6 +80,9 @@ from griptape_nodes.retained_mode.events.node_events import (
|
|
|
73
80
|
ListParametersOnNodeRequest,
|
|
74
81
|
ListParametersOnNodeResultFailure,
|
|
75
82
|
ListParametersOnNodeResultSuccess,
|
|
83
|
+
SendNodeMessageRequest,
|
|
84
|
+
SendNodeMessageResultFailure,
|
|
85
|
+
SendNodeMessageResultSuccess,
|
|
76
86
|
SerializedNodeCommands,
|
|
77
87
|
SerializedParameterValueTracker,
|
|
78
88
|
SerializedSelectedNodesCommands,
|
|
@@ -288,7 +298,30 @@ class NodeManager:
|
|
|
288
298
|
traceback.print_exc()
|
|
289
299
|
details = f"Could not create Node '{final_node_name}' of type '{request.node_type}': {err}"
|
|
290
300
|
logger.error(details)
|
|
291
|
-
|
|
301
|
+
|
|
302
|
+
# Check if we should create an Error Proxy node instead of failing
|
|
303
|
+
if request.create_error_proxy_on_failure:
|
|
304
|
+
try:
|
|
305
|
+
# Create ErrorProxyNode directly since it needs special initialization
|
|
306
|
+
node = ErrorProxyNode(
|
|
307
|
+
name=final_node_name,
|
|
308
|
+
original_node_type=request.node_type,
|
|
309
|
+
original_library_name=request.specific_library_name or "Unknown",
|
|
310
|
+
failure_reason=str(err),
|
|
311
|
+
metadata=request.metadata,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
logger.warning(
|
|
315
|
+
"Created Error Proxy (placeholder) node '%s' to substitute for failed '%s'",
|
|
316
|
+
final_node_name,
|
|
317
|
+
request.node_type,
|
|
318
|
+
)
|
|
319
|
+
except Exception as proxy_err:
|
|
320
|
+
details = f"Failed to create Error Proxy (placeholder) node: {proxy_err}"
|
|
321
|
+
logger.error(details)
|
|
322
|
+
return CreateNodeResultFailure(result_details=details)
|
|
323
|
+
else:
|
|
324
|
+
return CreateNodeResultFailure(result_details=details)
|
|
292
325
|
# Add it to the Flow.
|
|
293
326
|
parent_flow.add_node(node)
|
|
294
327
|
|
|
@@ -873,7 +906,7 @@ class NodeManager:
|
|
|
873
906
|
input_types=request.input_types,
|
|
874
907
|
output_type=request.output_type,
|
|
875
908
|
default_value=request.default_value,
|
|
876
|
-
user_defined=
|
|
909
|
+
user_defined=request.is_user_defined,
|
|
877
910
|
tooltip=request.tooltip,
|
|
878
911
|
tooltip_as_input=request.tooltip_as_input,
|
|
879
912
|
tooltip_as_property=request.tooltip_as_property,
|
|
@@ -1263,7 +1296,7 @@ class NodeManager:
|
|
|
1263
1296
|
|
|
1264
1297
|
return None
|
|
1265
1298
|
|
|
1266
|
-
def on_alter_parameter_details_request(self, request: AlterParameterDetailsRequest) -> ResultPayload: # noqa: C901, PLR0911
|
|
1299
|
+
def on_alter_parameter_details_request(self, request: AlterParameterDetailsRequest) -> ResultPayload: # noqa: C901, PLR0911, PLR0912
|
|
1267
1300
|
node_name = request.node_name
|
|
1268
1301
|
node = None
|
|
1269
1302
|
|
|
@@ -1292,6 +1325,24 @@ class NodeManager:
|
|
|
1292
1325
|
logger.error(details)
|
|
1293
1326
|
return AlterParameterDetailsResultFailure(result_details=details)
|
|
1294
1327
|
|
|
1328
|
+
# Handle ErrorProxyNode parameter alteration requests
|
|
1329
|
+
if isinstance(node, ErrorProxyNode):
|
|
1330
|
+
if request.initial_setup:
|
|
1331
|
+
# Record the alteration request for serialization replay
|
|
1332
|
+
node.record_initialization_request(request)
|
|
1333
|
+
|
|
1334
|
+
# Early return with warning - we're just preserving the original changes
|
|
1335
|
+
details = f"Parameter '{request.parameter_name}' alteration recorded for ErrorProxyNode '{node_name}'. Original node '{node.original_node_type}' had loading errors - preserving changes for correct recreation when dependency '{node.original_library_name}' is resolved."
|
|
1336
|
+
logger.warning(details)
|
|
1337
|
+
|
|
1338
|
+
result_details = ResultDetails(message=details, level="WARNING")
|
|
1339
|
+
return AlterParameterDetailsResultSuccess(result_details=result_details)
|
|
1340
|
+
|
|
1341
|
+
# Reject runtime parameter alterations on ErrorProxy
|
|
1342
|
+
details = f"Cannot modify parameter '{request.parameter_name}' on placeholder node '{node_name}'. This placeholder preserves your workflow structure but doesn't allow parameter modifications, as they could cause issues when the original node is restored."
|
|
1343
|
+
logger.error(details)
|
|
1344
|
+
return AlterParameterDetailsResultFailure(result_details=details)
|
|
1345
|
+
|
|
1295
1346
|
# Does the Element actually exist on the Node?
|
|
1296
1347
|
element = node.get_element_by_name_and_type(request.parameter_name)
|
|
1297
1348
|
if element is None:
|
|
@@ -1426,6 +1477,22 @@ class NodeManager:
|
|
|
1426
1477
|
logger.error(details)
|
|
1427
1478
|
return SetParameterValueResultFailure(result_details=details)
|
|
1428
1479
|
|
|
1480
|
+
# Handle ErrorProxyNode parameter value requests
|
|
1481
|
+
if isinstance(node, ErrorProxyNode):
|
|
1482
|
+
if request.initial_setup:
|
|
1483
|
+
# For initial_setup, actually create the parameter and set the value
|
|
1484
|
+
# This allows normal serialization to handle it, rather than recording the command
|
|
1485
|
+
node.on_attempt_set_parameter_value(param_name)
|
|
1486
|
+
# Continue with normal parameter value setting logic below
|
|
1487
|
+
logger.debug(
|
|
1488
|
+
"Created parameter '%s' on ErrorProxyNode '%s' during initial setup", param_name, node_name
|
|
1489
|
+
)
|
|
1490
|
+
else:
|
|
1491
|
+
# Reject runtime parameter value changes on ErrorProxy
|
|
1492
|
+
details = f"Cannot set parameter '{param_name}' on placeholder node '{node_name}'. This placeholder preserves your workflow structure but doesn't allow parameter changes, as they could cause issues when the original node is restored."
|
|
1493
|
+
logger.error(details)
|
|
1494
|
+
return SetParameterValueResultFailure(result_details=details)
|
|
1495
|
+
|
|
1429
1496
|
# Does the Parameter actually exist on the Node?
|
|
1430
1497
|
parameter = node.get_parameter_by_name(param_name)
|
|
1431
1498
|
if parameter is None:
|
|
@@ -1885,20 +1952,42 @@ class NodeManager:
|
|
|
1885
1952
|
library_used = node.metadata["library"]
|
|
1886
1953
|
# Get the library metadata so we can get the version.
|
|
1887
1954
|
library_metadata_request = GetLibraryMetadataRequest(library=library_used)
|
|
1888
|
-
|
|
1955
|
+
# Call LibraryManager directly to avoid error toasts when library is unavailable (expected for ErrorProxyNode)
|
|
1956
|
+
# Per https://github.com/griptape-ai/griptape-nodes/issues/1940
|
|
1957
|
+
library_metadata_result = GriptapeNodes.LibraryManager().get_library_metadata_request(
|
|
1958
|
+
library_metadata_request
|
|
1959
|
+
)
|
|
1960
|
+
|
|
1889
1961
|
if not isinstance(library_metadata_result, GetLibraryMetadataResultSuccess):
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1962
|
+
if isinstance(node, ErrorProxyNode):
|
|
1963
|
+
# For ErrorProxyNode, use descriptive message when original library unavailable
|
|
1964
|
+
library_version = "<version unavailable; workflow was saved when library was unable to be loaded>"
|
|
1965
|
+
library_details = LibraryNameAndVersion(library_name=library_used, library_version=library_version)
|
|
1966
|
+
details = f"Serializing Node '{node_name}' (original type: {node.original_node_type}) with unavailable library '{library_used}'. Saving as ErrorProxy with placeholder version. Fix the missing library and reload the workflow to restore the original node."
|
|
1967
|
+
logger.warning(details)
|
|
1968
|
+
else:
|
|
1969
|
+
# For regular nodes, this is still an error
|
|
1970
|
+
details = f"Attempted to serialize Node '{node_name}' to commands. Failed to get metadata for library '{library_used}'."
|
|
1971
|
+
logger.error(details)
|
|
1972
|
+
return SerializeNodeToCommandsResultFailure(result_details=details)
|
|
1973
|
+
else:
|
|
1974
|
+
library_version = library_metadata_result.metadata.library_version
|
|
1975
|
+
library_details = LibraryNameAndVersion(library_name=library_used, library_version=library_version)
|
|
1893
1976
|
|
|
1894
|
-
|
|
1895
|
-
|
|
1977
|
+
# Handle ErrorProxyNode serialization - serialize as original node type
|
|
1978
|
+
|
|
1979
|
+
if isinstance(node, ErrorProxyNode):
|
|
1980
|
+
serialized_node_type = node.original_node_type
|
|
1981
|
+
serialized_library_name = node.original_library_name
|
|
1982
|
+
else:
|
|
1983
|
+
serialized_node_type = node.__class__.__name__
|
|
1984
|
+
serialized_library_name = library_details.library_name
|
|
1896
1985
|
|
|
1897
1986
|
# Get the creation details.
|
|
1898
1987
|
create_node_request = CreateNodeRequest(
|
|
1899
|
-
node_type=
|
|
1988
|
+
node_type=serialized_node_type,
|
|
1900
1989
|
node_name=node_name,
|
|
1901
|
-
specific_library_name=
|
|
1990
|
+
specific_library_name=serialized_library_name,
|
|
1902
1991
|
metadata=copy.deepcopy(node.metadata),
|
|
1903
1992
|
# If it is actively resolving, mark as unresolved.
|
|
1904
1993
|
resolution=node.state.value,
|
|
@@ -1906,20 +1995,42 @@ class NodeManager:
|
|
|
1906
1995
|
)
|
|
1907
1996
|
|
|
1908
1997
|
# We're going to compare this node instance vs. a canonical one. Rez that one up.
|
|
1909
|
-
|
|
1998
|
+
# For ErrorProxyNode, we can't create a reference node, so skip comparison
|
|
1999
|
+
if isinstance(node, ErrorProxyNode):
|
|
2000
|
+
reference_node = None
|
|
2001
|
+
else:
|
|
2002
|
+
reference_node = type(node)(name="REFERENCE NODE")
|
|
1910
2003
|
|
|
1911
2004
|
# Now creation or alteration of all of the elements.
|
|
1912
2005
|
element_modification_commands = []
|
|
1913
2006
|
for parameter in node.parameters:
|
|
1914
2007
|
# Create the parameter, or alter it on the existing node
|
|
1915
2008
|
if parameter.user_defined:
|
|
1916
|
-
#
|
|
2009
|
+
# Always serialize user-defined parameters regardless of node type
|
|
2010
|
+
param_dict = parameter.to_dict()
|
|
2011
|
+
param_dict["initial_setup"] = True
|
|
2012
|
+
add_param_request = AddParameterToNodeRequest.create(**param_dict)
|
|
2013
|
+
element_modification_commands.append(add_param_request)
|
|
2014
|
+
elif isinstance(node, ErrorProxyNode):
|
|
2015
|
+
# For ErrorProxyNode, replay all recorded initialization requests for this parameter
|
|
2016
|
+
recorded_requests = node.get_recorded_initialization_requests()
|
|
2017
|
+
matching_requests = [
|
|
2018
|
+
recorded_request
|
|
2019
|
+
for recorded_request in recorded_requests
|
|
2020
|
+
if (
|
|
2021
|
+
hasattr(recorded_request, "parameter_name")
|
|
2022
|
+
and getattr(recorded_request, "parameter_name", None) == parameter.name
|
|
2023
|
+
)
|
|
2024
|
+
]
|
|
2025
|
+
element_modification_commands.extend(matching_requests)
|
|
2026
|
+
elif reference_node is None:
|
|
2027
|
+
# Normal node with no reference - treat all parameters as needing serialization
|
|
1917
2028
|
param_dict = parameter.to_dict()
|
|
1918
2029
|
param_dict["initial_setup"] = True
|
|
1919
2030
|
add_param_request = AddParameterToNodeRequest.create(**param_dict)
|
|
1920
2031
|
element_modification_commands.append(add_param_request)
|
|
1921
2032
|
else:
|
|
1922
|
-
#
|
|
2033
|
+
# Normal node - compare against reference node
|
|
1923
2034
|
diff = NodeManager._manage_alter_details(parameter, reference_node)
|
|
1924
2035
|
relevant = False
|
|
1925
2036
|
for key in diff:
|
|
@@ -1934,6 +2045,10 @@ class NodeManager:
|
|
|
1934
2045
|
|
|
1935
2046
|
# Now assignment of values to all of the parameters.
|
|
1936
2047
|
set_value_commands = []
|
|
2048
|
+
|
|
2049
|
+
# ErrorProxyNode uses normal parameter serialization now since we create real parameters
|
|
2050
|
+
# Only AlterParameterDetailsRequest commands are recorded and replayed
|
|
2051
|
+
# Normal node - use current parameter values
|
|
1937
2052
|
for parameter in node.parameters:
|
|
1938
2053
|
# SetParameterValueRequest event
|
|
1939
2054
|
set_param_value_requests = NodeManager._handle_parameter_value_saving(
|
|
@@ -2298,6 +2413,7 @@ class NodeManager:
|
|
|
2298
2413
|
value: Any,
|
|
2299
2414
|
serialized_parameter_value_tracker: SerializedParameterValueTracker,
|
|
2300
2415
|
unique_parameter_uuid_to_values: dict,
|
|
2416
|
+
parameter: Parameter,
|
|
2301
2417
|
parameter_name: str,
|
|
2302
2418
|
node_name: str,
|
|
2303
2419
|
*,
|
|
@@ -2321,8 +2437,10 @@ class NodeManager:
|
|
|
2321
2437
|
case SerializedParameterValueTracker.TrackerState.NOT_IN_TRACKER:
|
|
2322
2438
|
# This value is new for us.
|
|
2323
2439
|
|
|
2324
|
-
#
|
|
2325
|
-
|
|
2440
|
+
# Check if parameter is marked as non-serializable (e.g., ImageDrivers, PromptDrivers, file handles)
|
|
2441
|
+
if not parameter.serializable:
|
|
2442
|
+
serialized_parameter_value_tracker.add_as_not_serializable(value_id)
|
|
2443
|
+
return None
|
|
2326
2444
|
|
|
2327
2445
|
# Check if we can serialize it.
|
|
2328
2446
|
try:
|
|
@@ -2403,12 +2521,13 @@ class NodeManager:
|
|
|
2403
2521
|
value=internal_value,
|
|
2404
2522
|
serialized_parameter_value_tracker=serialized_parameter_value_tracker,
|
|
2405
2523
|
unique_parameter_uuid_to_values=unique_parameter_uuid_to_values,
|
|
2524
|
+
parameter=parameter,
|
|
2406
2525
|
is_output=False,
|
|
2407
2526
|
parameter_name=parameter.name,
|
|
2408
2527
|
node_name=node.name,
|
|
2409
2528
|
)
|
|
2410
2529
|
if internal_command is None:
|
|
2411
|
-
details = f"Attempted to serialize set value for parameter '{parameter.name}' on node '{node.name}'. The set value will not be restored in anything that attempts to deserialize or save this node. The value for this parameter was not serialized because it did not match Griptape Nodes' criteria for serializability. To remedy, either update the value's type to support serializability or mark the parameter as not serializable."
|
|
2530
|
+
details = f"Attempted to serialize set value for parameter '{parameter.name}' on node '{node.name}'. The set value will not be restored in anything that attempts to deserialize or save this node. The value for this parameter was not serialized because it did not match Griptape Nodes' criteria for serializability. To remedy, either update the value's type to support serializability or mark the parameter as not serializable by setting serializable=False when creating the parameter."
|
|
2412
2531
|
logger.warning(details)
|
|
2413
2532
|
else:
|
|
2414
2533
|
commands.append(internal_command)
|
|
@@ -2417,12 +2536,13 @@ class NodeManager:
|
|
|
2417
2536
|
value=output_value,
|
|
2418
2537
|
serialized_parameter_value_tracker=serialized_parameter_value_tracker,
|
|
2419
2538
|
unique_parameter_uuid_to_values=unique_parameter_uuid_to_values,
|
|
2539
|
+
parameter=parameter,
|
|
2420
2540
|
is_output=True,
|
|
2421
2541
|
parameter_name=parameter.name,
|
|
2422
2542
|
node_name=node.name,
|
|
2423
2543
|
)
|
|
2424
2544
|
if output_command is None:
|
|
2425
|
-
details = f"Attempted to serialize output value for parameter '{parameter.name}' on node '{node.name}'. The output value will not be restored in anything that attempts to deserialize or save this node. The value for this parameter was not serialized because it did not match Griptape Nodes' criteria for serializability. To remedy, either update the value's type to support serializability or mark the parameter as not serializable."
|
|
2545
|
+
details = f"Attempted to serialize output value for parameter '{parameter.name}' on node '{node.name}'. The output value will not be restored in anything that attempts to deserialize or save this node. The value for this parameter was not serialized because it did not match Griptape Nodes' criteria for serializability. To remedy, either update the value's type to support serializability or mark the parameter as not serializable by setting serializable=False when creating the parameter."
|
|
2426
2546
|
logger.warning(details)
|
|
2427
2547
|
else:
|
|
2428
2548
|
commands.append(output_command)
|
|
@@ -2533,3 +2653,66 @@ class NodeManager:
|
|
|
2533
2653
|
return SetLockNodeStateResultFailure(result_details=details)
|
|
2534
2654
|
node.lock = request.lock
|
|
2535
2655
|
return SetLockNodeStateResultSuccess(node_name=node_name, locked=node.lock)
|
|
2656
|
+
|
|
2657
|
+
def on_send_node_message_request(self, request: SendNodeMessageRequest) -> ResultPayload:
|
|
2658
|
+
"""Handle a SendNodeMessageRequest by calling the node's message callback.
|
|
2659
|
+
|
|
2660
|
+
Args:
|
|
2661
|
+
request: The SendNodeMessageRequest containing message details
|
|
2662
|
+
|
|
2663
|
+
Returns:
|
|
2664
|
+
ResultPayload: Success or failure result with callback response
|
|
2665
|
+
"""
|
|
2666
|
+
node_name = request.node_name
|
|
2667
|
+
node = None
|
|
2668
|
+
|
|
2669
|
+
if node_name is None:
|
|
2670
|
+
# Get from the current context
|
|
2671
|
+
if not GriptapeNodes.ContextManager().has_current_node():
|
|
2672
|
+
details = "Attempted to send message to Node from Current Context. Failed because the Current Context is empty."
|
|
2673
|
+
logger.error(details)
|
|
2674
|
+
return SendNodeMessageResultFailure(result_details=details)
|
|
2675
|
+
|
|
2676
|
+
node = GriptapeNodes.ContextManager().get_current_node()
|
|
2677
|
+
node_name = node.name
|
|
2678
|
+
|
|
2679
|
+
if node is None:
|
|
2680
|
+
# Find the node by name
|
|
2681
|
+
obj_mgr = GriptapeNodes.ObjectManager()
|
|
2682
|
+
node = obj_mgr.attempt_get_object_by_name_as_type(node_name, BaseNode)
|
|
2683
|
+
if node is None:
|
|
2684
|
+
details = f"Attempted to send message to Node '{node_name}', but no such Node was found."
|
|
2685
|
+
logger.error(details)
|
|
2686
|
+
return SendNodeMessageResultFailure(result_details=details)
|
|
2687
|
+
|
|
2688
|
+
# Validate optional_element_name if specified
|
|
2689
|
+
if request.optional_element_name is not None:
|
|
2690
|
+
element = node.root_ui_element.find_element_by_name(request.optional_element_name)
|
|
2691
|
+
if element is None:
|
|
2692
|
+
details = f"Attempted to send message to Node '{node_name}' with element '{request.optional_element_name}', but no such element was found."
|
|
2693
|
+
logger.error(details)
|
|
2694
|
+
return SendNodeMessageResultFailure(result_details=details, altered_workflow_state=False)
|
|
2695
|
+
|
|
2696
|
+
# Call the node's message callback
|
|
2697
|
+
callback_result = node.on_node_message_received(
|
|
2698
|
+
optional_element_name=request.optional_element_name,
|
|
2699
|
+
message_type=request.message_type,
|
|
2700
|
+
message=request.message,
|
|
2701
|
+
)
|
|
2702
|
+
|
|
2703
|
+
if not callback_result.success:
|
|
2704
|
+
details = f"Failed to handle message for Node '{node_name}': {callback_result.details}"
|
|
2705
|
+
logger.warning(details)
|
|
2706
|
+
return SendNodeMessageResultFailure(
|
|
2707
|
+
result_details=callback_result.details,
|
|
2708
|
+
response=callback_result.response,
|
|
2709
|
+
altered_workflow_state=callback_result.altered_workflow_state,
|
|
2710
|
+
)
|
|
2711
|
+
|
|
2712
|
+
details = f"Successfully sent message to Node '{node_name}': {callback_result.details}"
|
|
2713
|
+
logger.debug(details)
|
|
2714
|
+
return SendNodeMessageResultSuccess(
|
|
2715
|
+
result_details=callback_result.details,
|
|
2716
|
+
response=callback_result.response,
|
|
2717
|
+
altered_workflow_state=callback_result.altered_workflow_state,
|
|
2718
|
+
)
|
|
@@ -6,6 +6,11 @@ import importlib.metadata
|
|
|
6
6
|
import json
|
|
7
7
|
from typing import Literal
|
|
8
8
|
|
|
9
|
+
import httpx
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
9
14
|
engine_version = importlib.metadata.version("griptape_nodes")
|
|
10
15
|
|
|
11
16
|
|
|
@@ -49,3 +54,73 @@ def get_complete_version_string() -> str:
|
|
|
49
54
|
if commit_id is None:
|
|
50
55
|
return f"{version} ({source})"
|
|
51
56
|
return f"{version} ({source} - {commit_id})"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_latest_version_pypi(package: str, pypi_url: str) -> str:
|
|
60
|
+
"""Gets the latest version from PyPI.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
package: The name of the package to fetch the latest version for.
|
|
64
|
+
pypi_url: The PyPI URL template to use.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
str: Latest release tag (e.g., "v0.31.4") or current version if fetch fails.
|
|
68
|
+
"""
|
|
69
|
+
version = get_current_version()
|
|
70
|
+
update_url = pypi_url.format(package=package)
|
|
71
|
+
|
|
72
|
+
with httpx.Client(timeout=30.0) as client:
|
|
73
|
+
try:
|
|
74
|
+
response = client.get(update_url)
|
|
75
|
+
except httpx.RequestError as e:
|
|
76
|
+
console.print(f"[red]Error fetching latest version due to error: [/red][cyan]{e}[/cyan]")
|
|
77
|
+
console.print(
|
|
78
|
+
f"[red]Please check your internet connection or if you can access the following update url: [/red] [cyan]{update_url}[/cyan]"
|
|
79
|
+
)
|
|
80
|
+
return version
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
response.raise_for_status()
|
|
84
|
+
data = response.json()
|
|
85
|
+
if "info" in data and "version" in data["info"]:
|
|
86
|
+
version = f"v{data['info']['version']}"
|
|
87
|
+
except httpx.HTTPStatusError as e:
|
|
88
|
+
console.print(f"[red]Error fetching latest version: {e}[/red]")
|
|
89
|
+
|
|
90
|
+
return version
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_latest_version_git(package: str, github_url: str, latest_tag: str) -> str:
|
|
94
|
+
"""Gets the latest version from Git.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
package: The name of the package to fetch the latest version for.
|
|
98
|
+
github_url: The GitHub URL template to use.
|
|
99
|
+
latest_tag: The tag to fetch (usually 'latest').
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
str: Latest commit SHA (first 7 characters) or current version if fetch fails.
|
|
103
|
+
"""
|
|
104
|
+
version = get_current_version()
|
|
105
|
+
revision = latest_tag
|
|
106
|
+
update_url = github_url.format(package=package, revision=revision)
|
|
107
|
+
|
|
108
|
+
with httpx.Client(timeout=30.0) as client:
|
|
109
|
+
try:
|
|
110
|
+
response = client.get(update_url)
|
|
111
|
+
except httpx.RequestError as e:
|
|
112
|
+
console.print(f"[red]Error fetching latest version due to error: [/red][cyan]{e}[/cyan]")
|
|
113
|
+
console.print(
|
|
114
|
+
f"[red]Please check your internet connection or if you can access the following update url: [/red] [cyan]{update_url}[/cyan]"
|
|
115
|
+
)
|
|
116
|
+
return version
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
response.raise_for_status()
|
|
120
|
+
data = response.json()
|
|
121
|
+
if "object" in data and "sha" in data["object"]:
|
|
122
|
+
version = data["object"]["sha"][:7]
|
|
123
|
+
except httpx.HTTPStatusError as e:
|
|
124
|
+
console.print(f"[red]Error fetching latest version: {e}[/red]")
|
|
125
|
+
|
|
126
|
+
return version
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
griptape_nodes/__init__.py,sha256=
|
|
1
|
+
griptape_nodes/__init__.py,sha256=ca4ec8ef95679e0a98c8e75a539ee1a6eb00c8bf2d1d88bf0e44edb9b778e192,37367
|
|
2
2
|
griptape_nodes/app/.python-version,sha256=7b55f8e67b5623c4bef3fa691288da9437d79d3aba156de48d481db32ac7d16d,5
|
|
3
3
|
griptape_nodes/app/__init__.py,sha256=0c1f834ec81c3676e6102957128bb0cc686b9a8de01c10965c1f4190f1a97502,90
|
|
4
4
|
griptape_nodes/app/api.py,sha256=46a36af068a4784b0317daede79befd59198320c3934ee1b84c74b297108774f,6925
|
|
5
|
-
griptape_nodes/app/app.py,sha256=
|
|
5
|
+
griptape_nodes/app/app.py,sha256=4d494cb0e1ba87c288b19a76c01015629c104fdf7a8668b6abf42e6e8baeaade,17984
|
|
6
6
|
griptape_nodes/app/watch.py,sha256=413353c7811b54440276277250d766b3be30edf8eb8c128069dbb52d40e9e962,2064
|
|
7
7
|
griptape_nodes/bootstrap/__init__.py,sha256=10dbf7488cd0f53b6546b835cb87b80a7a01a49685a454a43694c5055f17e4bb,25
|
|
8
8
|
griptape_nodes/bootstrap/workflow_executors/__init__.py,sha256=a728cdf35f9e2ed8f21021582d73ad3028b18a223da818b9c9a95df3a88cec49,34
|
|
9
|
-
griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py,sha256=
|
|
9
|
+
griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py,sha256=f09128692368e073d18cc602bcc0c81af8317eb4bfff486b30154262eb45f578,9274
|
|
10
10
|
griptape_nodes/bootstrap/workflow_executors/subprocess_workflow_executor.py,sha256=b610be5ba3b459d1f0f0ee6a01fa104bed225d6081ae1db42626de8c7bc6c90c,3347
|
|
11
11
|
griptape_nodes/bootstrap/workflow_executors/workflow_executor.py,sha256=945000fb96d6cabd8a7f53324b9d2f5f549e1bb976ce66d2adbe7f932c8822ba,417
|
|
12
12
|
griptape_nodes/drivers/__init__.py,sha256=b479a21509fab89c855610b63eba87811507ddddf20eca8c4295aa45ab266aa0,42
|
|
@@ -17,9 +17,9 @@ griptape_nodes/drivers/storage/local_storage_driver.py,sha256=3e912fb41fd35a0e5c
|
|
|
17
17
|
griptape_nodes/drivers/storage/storage_backend.py,sha256=dd0048c2b80f73592b04888f60ba0adacc2120f0e22899e7b9c384772c7bcb77,184
|
|
18
18
|
griptape_nodes/exe_types/__init__.py,sha256=c061b02865fdf9349aad415b5e90ef754fc9ede5c86d64c197f3422ce65af86f,32
|
|
19
19
|
griptape_nodes/exe_types/connections.py,sha256=ffe54dcdfe8a6b2eb6433265497f8b9474d4873f82285f940ec6d92c9d25e969,12435
|
|
20
|
-
griptape_nodes/exe_types/core_types.py,sha256=
|
|
20
|
+
griptape_nodes/exe_types/core_types.py,sha256=6cd742f545f89d7eb23aa6fdc10c8e706e035f459a57ae4977a630edee6b9e94,71471
|
|
21
21
|
griptape_nodes/exe_types/flow.py,sha256=a42793af1f32ad480bc3553dc90c42edaaf3263c8fdaf6a0fa91b44132aeb7e3,5716
|
|
22
|
-
griptape_nodes/exe_types/node_types.py,sha256=
|
|
22
|
+
griptape_nodes/exe_types/node_types.py,sha256=7c497246e4673e663e6ce3501bb632db5dbd2d2bc01c0117b064632cdce5f47d,59948
|
|
23
23
|
griptape_nodes/exe_types/type_validator.py,sha256=453cf5bd7d3d8f34291e1a33213309d2c88e6545efb0444386b0298dd68cd563,1120
|
|
24
24
|
griptape_nodes/machines/__init__.py,sha256=bf48e4c2bf8214e2e67c461442f5fc04a40b39dbe14ac03ab685e474770f1941,30
|
|
25
25
|
griptape_nodes/machines/control_flow.py,sha256=ac7e9d4555eb0aa5c30cfa182d4df542e661f24b8871113bb26962de917451d5,9843
|
|
@@ -47,10 +47,10 @@ griptape_nodes/retained_mode/events/flow_events.py,sha256=084eda147bc1c98ea28b48
|
|
|
47
47
|
griptape_nodes/retained_mode/events/generate_request_payload_schemas.py,sha256=3d0d104590140658d22068c1f1085851e4664ab7e62ec27a5d57328092a2d772,1102
|
|
48
48
|
griptape_nodes/retained_mode/events/library_events.py,sha256=f4a54c1c0e556b36377d71089b7d599b2fab278dc0c4d8276b84b354f9b2f0f8,17629
|
|
49
49
|
griptape_nodes/retained_mode/events/logger_events.py,sha256=8d8971ccfa26802b09b8fb49d339d60610fc4097c2f2a0b8c5f0a10e2b95bb28,705
|
|
50
|
-
griptape_nodes/retained_mode/events/node_events.py,sha256=
|
|
50
|
+
griptape_nodes/retained_mode/events/node_events.py,sha256=9402c9c59b07e3bc4f706361987441a82f9813954d7ab2b007ef671d3fe189dc,27298
|
|
51
51
|
griptape_nodes/retained_mode/events/object_events.py,sha256=7096aa114ef72f37f5451c49ac5a84a65f1e4ebfa00e12a95cacb027ebd50894,2631
|
|
52
52
|
griptape_nodes/retained_mode/events/os_events.py,sha256=5f49a6ca4febe6deaea5a43c7960a50fb276e40897da082c02ec4c6525bd571d,8085
|
|
53
|
-
griptape_nodes/retained_mode/events/parameter_events.py,sha256=
|
|
53
|
+
griptape_nodes/retained_mode/events/parameter_events.py,sha256=1607dd828ef4c3bdfef1ee22c3e8fcce33f432028d0e6a230e3a902cb85b9e86,18549
|
|
54
54
|
griptape_nodes/retained_mode/events/payload_registry.py,sha256=abec3152aa7adef84d8fe3e5d491891e706485479f70202b3e830ddca0511042,1691
|
|
55
55
|
griptape_nodes/retained_mode/events/secrets_events.py,sha256=7c2c3738c15fc41f054d9b38c9ba239b59ea36f85c8eda0dca54215fbe7e8e43,4156
|
|
56
56
|
griptape_nodes/retained_mode/events/static_file_events.py,sha256=73c90a92bc403d9c6b13d7ec95da56b7078ad42e13fb5f9d1d6c3fefa4917a13,3764
|
|
@@ -65,7 +65,7 @@ griptape_nodes/retained_mode/managers/config_manager.py,sha256=d75b211dc72329f4b
|
|
|
65
65
|
griptape_nodes/retained_mode/managers/context_manager.py,sha256=0e218d874f5367baec2c4717aaa07d62b87689eb41cb9f4b3c5ec6334381412f,22930
|
|
66
66
|
griptape_nodes/retained_mode/managers/engine_identity_manager.py,sha256=181073ec72412553725cb191740bea0e08a131107f6235aa744c0b3029da7548,4409
|
|
67
67
|
griptape_nodes/retained_mode/managers/event_manager.py,sha256=ac6a1e18ed004d977dc3c1a6d510c7a0e0c363227e5eac6218989d6228c7fd06,7201
|
|
68
|
-
griptape_nodes/retained_mode/managers/flow_manager.py,sha256=
|
|
68
|
+
griptape_nodes/retained_mode/managers/flow_manager.py,sha256=7922e81dc89ca57b7657a9ec9e84dd086165168fe03896e06b13bb7162ee2e16,110336
|
|
69
69
|
griptape_nodes/retained_mode/managers/library_lifecycle/__init__.py,sha256=22aefd5714dd113884c417c559771e26080366a4ba5f73a4cd713d5f015c955c,1340
|
|
70
70
|
griptape_nodes/retained_mode/managers/library_lifecycle/data_models.py,sha256=7ef00fd1569818f1d897f2a0dd12f881d265a6ac9af144efa4ff82e3dafde749,6723
|
|
71
71
|
griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py,sha256=c44e88de3196c524a452db9979bc24d00bee9083f62732c1378b4daaafcc126d,14758
|
|
@@ -79,7 +79,7 @@ griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/sandb
|
|
|
79
79
|
griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance.py,sha256=7021abf8c4354655418944d97a960429d5613e00b879b718ae6a6ff2b23755e3,894
|
|
80
80
|
griptape_nodes/retained_mode/managers/library_lifecycle/library_status.py,sha256=2b750407301d098f70a61c816cbc4360fd10e37698be12d9fcfcfbfd2cdc3de7,443
|
|
81
81
|
griptape_nodes/retained_mode/managers/library_manager.py,sha256=c89cf240000f6bcf940a4e3106d968694787f51417ec5f90b1738c0852294f11,98816
|
|
82
|
-
griptape_nodes/retained_mode/managers/node_manager.py,sha256=
|
|
82
|
+
griptape_nodes/retained_mode/managers/node_manager.py,sha256=1235d54ca8be9b84b59519984c9ac2fe946a51dc43e2659b36b6c1e376b32804,145538
|
|
83
83
|
griptape_nodes/retained_mode/managers/object_manager.py,sha256=b483de02217de29b48a57c4cdbda858104da5dacd1817edf69324b57cef25991,12403
|
|
84
84
|
griptape_nodes/retained_mode/managers/operation_manager.py,sha256=95390c66569a71382d579a15f9817a1c6f31b31f55fcbc17d5e834ef8593b369,20137
|
|
85
85
|
griptape_nodes/retained_mode/managers/os_manager.py,sha256=6cf2580a42404a2b1b5ae03da832825d3aae18469538c76005358e3b5d1699b0,34347
|
|
@@ -113,7 +113,7 @@ griptape_nodes/utils/dict_utils.py,sha256=932962e4c39fcd2a2bd1af259977d80554bf35
|
|
|
113
113
|
griptape_nodes/utils/image_preview.py,sha256=361608aa885117dbdb16958812f64774f2cb3cafc975406f0b846f340b126b5c,4480
|
|
114
114
|
griptape_nodes/utils/metaclasses.py,sha256=4522b202f669a47fe16ccba0994988afc42a3a0d6c618e2e44d7d0c9b0f83bc4,287
|
|
115
115
|
griptape_nodes/utils/uv_utils.py,sha256=64adfb2e669c29fc4c54a91c20ec89df91ce5e057ab05584f42ce028f99a454d,519
|
|
116
|
-
griptape_nodes/utils/version_utils.py,sha256=
|
|
116
|
+
griptape_nodes/utils/version_utils.py,sha256=63e1c97c95ba271bb3fe33a71f1322cbea6631ab8746763eec13b76a51a6c3e4,4318
|
|
117
117
|
griptape_nodes/version_compatibility/__init__.py,sha256=24ccf5b01ed9b23ea94b54b9b1db0f474927f3db35034b01d24148bf280961fa,74
|
|
118
118
|
griptape_nodes/version_compatibility/versions/__init__.py,sha256=3d64b1336f0b3d47417513c0f7c8f84545afb99e0da9f5f575acb6554e92a8fc,74
|
|
119
119
|
griptape_nodes/version_compatibility/versions/v0_39_0/__init__.py,sha256=db588a945a6c9815b85ac01ec520f458c0099ec62632adac21b0de602f37d5f7,62
|
|
@@ -121,7 +121,7 @@ griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_re
|
|
|
121
121
|
griptape_nodes/version_compatibility/workflow_versions/__init__.py,sha256=cf95c38248b3a0d072097a72a37e217ec24a16c5a53876c3ea18337d81fdb9b7,52
|
|
122
122
|
griptape_nodes/version_compatibility/workflow_versions/v0_7_0/__init__.py,sha256=2333cf9862bcea1dacc1f1864ce1f255c04894e9e0e928e0590ce56dfde7826a,51
|
|
123
123
|
griptape_nodes/version_compatibility/workflow_versions/v0_7_0/local_executor_argument_addition.py,sha256=f4f725029fcc9b920fb5de728f95d24b9fb1ed062689fbe14e5cb6d02801666a,2018
|
|
124
|
-
griptape_nodes-0.
|
|
125
|
-
griptape_nodes-0.
|
|
126
|
-
griptape_nodes-0.
|
|
127
|
-
griptape_nodes-0.
|
|
124
|
+
griptape_nodes-0.50.0.dist-info/WHEEL,sha256=76443c98c0efcfdd1191eac5fa1d8223dba1c474dbd47676674a255e7ca48770,79
|
|
125
|
+
griptape_nodes-0.50.0.dist-info/entry_points.txt,sha256=aaf7afa9ddc155b015e5371a9ed9c09b4a2ea9aa982a1b113b7a641729962d63,82
|
|
126
|
+
griptape_nodes-0.50.0.dist-info/METADATA,sha256=461e5adb7bd3203d87800235d546f715d6467b8fb7f28916d95531544f51efcd,4980
|
|
127
|
+
griptape_nodes-0.50.0.dist-info/RECORD,,
|
|
File without changes
|