griptape-nodes 0.41.0__py3-none-any.whl → 0.43.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 +0 -0
- griptape_nodes/app/.python-version +0 -0
- griptape_nodes/app/__init__.py +1 -10
- griptape_nodes/app/api.py +199 -0
- griptape_nodes/app/app.py +140 -222
- griptape_nodes/app/watch.py +4 -2
- griptape_nodes/bootstrap/__init__.py +0 -0
- griptape_nodes/bootstrap/bootstrap_script.py +0 -0
- griptape_nodes/bootstrap/register_libraries_script.py +0 -0
- griptape_nodes/bootstrap/structure_config.yaml +0 -0
- griptape_nodes/bootstrap/workflow_executors/__init__.py +0 -0
- griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +0 -0
- griptape_nodes/bootstrap/workflow_executors/workflow_executor.py +0 -0
- griptape_nodes/bootstrap/workflow_runners/__init__.py +0 -0
- griptape_nodes/bootstrap/workflow_runners/bootstrap_workflow_runner.py +0 -0
- griptape_nodes/bootstrap/workflow_runners/local_workflow_runner.py +0 -0
- griptape_nodes/bootstrap/workflow_runners/subprocess_workflow_runner.py +6 -2
- griptape_nodes/bootstrap/workflow_runners/workflow_runner.py +0 -0
- griptape_nodes/drivers/__init__.py +0 -0
- griptape_nodes/drivers/storage/__init__.py +0 -0
- griptape_nodes/drivers/storage/base_storage_driver.py +0 -0
- griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +0 -0
- griptape_nodes/drivers/storage/local_storage_driver.py +5 -3
- griptape_nodes/drivers/storage/storage_backend.py +0 -0
- griptape_nodes/exe_types/__init__.py +0 -0
- griptape_nodes/exe_types/connections.py +0 -0
- griptape_nodes/exe_types/core_types.py +0 -0
- griptape_nodes/exe_types/flow.py +68 -368
- griptape_nodes/exe_types/node_types.py +17 -1
- griptape_nodes/exe_types/type_validator.py +0 -0
- griptape_nodes/machines/__init__.py +0 -0
- griptape_nodes/machines/control_flow.py +52 -20
- griptape_nodes/machines/fsm.py +16 -2
- griptape_nodes/machines/node_resolution.py +16 -14
- griptape_nodes/mcp_server/__init__.py +1 -0
- griptape_nodes/mcp_server/server.py +126 -0
- griptape_nodes/mcp_server/ws_request_manager.py +268 -0
- griptape_nodes/node_library/__init__.py +0 -0
- griptape_nodes/node_library/advanced_node_library.py +0 -0
- griptape_nodes/node_library/library_registry.py +0 -0
- griptape_nodes/node_library/workflow_registry.py +2 -2
- griptape_nodes/py.typed +0 -0
- griptape_nodes/retained_mode/__init__.py +0 -0
- griptape_nodes/retained_mode/events/__init__.py +0 -0
- griptape_nodes/retained_mode/events/agent_events.py +70 -8
- griptape_nodes/retained_mode/events/app_events.py +137 -12
- griptape_nodes/retained_mode/events/arbitrary_python_events.py +23 -0
- griptape_nodes/retained_mode/events/base_events.py +13 -31
- griptape_nodes/retained_mode/events/config_events.py +87 -11
- griptape_nodes/retained_mode/events/connection_events.py +56 -5
- griptape_nodes/retained_mode/events/context_events.py +27 -4
- griptape_nodes/retained_mode/events/execution_events.py +99 -14
- griptape_nodes/retained_mode/events/flow_events.py +165 -7
- griptape_nodes/retained_mode/events/generate_request_payload_schemas.py +0 -0
- griptape_nodes/retained_mode/events/library_events.py +195 -17
- griptape_nodes/retained_mode/events/logger_events.py +11 -0
- griptape_nodes/retained_mode/events/node_events.py +242 -22
- griptape_nodes/retained_mode/events/object_events.py +40 -4
- griptape_nodes/retained_mode/events/os_events.py +116 -3
- griptape_nodes/retained_mode/events/parameter_events.py +212 -8
- griptape_nodes/retained_mode/events/payload_registry.py +0 -0
- griptape_nodes/retained_mode/events/secrets_events.py +59 -7
- griptape_nodes/retained_mode/events/static_file_events.py +57 -4
- griptape_nodes/retained_mode/events/validation_events.py +39 -4
- griptape_nodes/retained_mode/events/workflow_events.py +188 -17
- griptape_nodes/retained_mode/griptape_nodes.py +89 -363
- griptape_nodes/retained_mode/managers/__init__.py +0 -0
- griptape_nodes/retained_mode/managers/agent_manager.py +49 -23
- griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +0 -0
- griptape_nodes/retained_mode/managers/config_manager.py +0 -0
- griptape_nodes/retained_mode/managers/context_manager.py +0 -0
- griptape_nodes/retained_mode/managers/engine_identity_manager.py +146 -0
- griptape_nodes/retained_mode/managers/event_manager.py +14 -2
- griptape_nodes/retained_mode/managers/flow_manager.py +751 -64
- griptape_nodes/retained_mode/managers/library_lifecycle/__init__.py +45 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/data_models.py +191 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +346 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_fsm.py +439 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/__init__.py +17 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/base.py +82 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/github.py +116 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +352 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/package.py +104 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/sandbox.py +155 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance.py +18 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_status.py +12 -0
- griptape_nodes/retained_mode/managers/library_manager.py +255 -40
- griptape_nodes/retained_mode/managers/node_manager.py +120 -103
- griptape_nodes/retained_mode/managers/object_manager.py +11 -3
- griptape_nodes/retained_mode/managers/operation_manager.py +0 -0
- griptape_nodes/retained_mode/managers/os_manager.py +582 -8
- griptape_nodes/retained_mode/managers/secrets_manager.py +4 -0
- griptape_nodes/retained_mode/managers/session_manager.py +328 -0
- griptape_nodes/retained_mode/managers/settings.py +7 -0
- griptape_nodes/retained_mode/managers/static_files_manager.py +0 -0
- griptape_nodes/retained_mode/managers/version_compatibility_manager.py +2 -2
- griptape_nodes/retained_mode/managers/workflow_manager.py +722 -456
- griptape_nodes/retained_mode/retained_mode.py +44 -0
- griptape_nodes/retained_mode/utils/__init__.py +0 -0
- griptape_nodes/retained_mode/utils/engine_identity.py +141 -27
- griptape_nodes/retained_mode/utils/name_generator.py +0 -0
- griptape_nodes/traits/__init__.py +0 -0
- griptape_nodes/traits/add_param_button.py +0 -0
- griptape_nodes/traits/button.py +0 -0
- griptape_nodes/traits/clamp.py +0 -0
- griptape_nodes/traits/compare.py +0 -0
- griptape_nodes/traits/compare_images.py +0 -0
- griptape_nodes/traits/file_system_picker.py +127 -0
- griptape_nodes/traits/minmax.py +0 -0
- griptape_nodes/traits/options.py +0 -0
- griptape_nodes/traits/slider.py +0 -0
- griptape_nodes/traits/trait_registry.py +0 -0
- griptape_nodes/traits/traits.json +0 -0
- griptape_nodes/updater/__init__.py +2 -2
- griptape_nodes/updater/__main__.py +0 -0
- griptape_nodes/utils/__init__.py +0 -0
- griptape_nodes/utils/dict_utils.py +0 -0
- griptape_nodes/utils/image_preview.py +128 -0
- griptape_nodes/utils/metaclasses.py +0 -0
- griptape_nodes/version_compatibility/__init__.py +0 -0
- griptape_nodes/version_compatibility/versions/__init__.py +0 -0
- griptape_nodes/version_compatibility/versions/v0_39_0/__init__.py +0 -0
- griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +5 -5
- griptape_nodes-0.43.0.dist-info/METADATA +90 -0
- griptape_nodes-0.43.0.dist-info/RECORD +129 -0
- griptape_nodes-0.43.0.dist-info/WHEEL +4 -0
- {griptape_nodes-0.41.0.dist-info → griptape_nodes-0.43.0.dist-info}/entry_points.txt +1 -0
- griptape_nodes/app/app_sessions.py +0 -458
- griptape_nodes/retained_mode/utils/session_persistence.py +0 -105
- griptape_nodes-0.41.0.dist-info/METADATA +0 -78
- griptape_nodes-0.41.0.dist-info/RECORD +0 -112
- griptape_nodes-0.41.0.dist-info/WHEEL +0 -4
- griptape_nodes-0.41.0.dist-info/licenses/LICENSE +0 -201
|
@@ -7,14 +7,12 @@ import re
|
|
|
7
7
|
import uuid
|
|
8
8
|
from dataclasses import dataclass
|
|
9
9
|
from datetime import UTC, datetime
|
|
10
|
-
from typing import
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
11
|
|
|
12
|
-
import httpx
|
|
13
|
-
|
|
14
|
-
from griptape_nodes.exe_types.core_types import BaseNodeElement, Parameter, ParameterContainer, ParameterGroup
|
|
15
12
|
from griptape_nodes.exe_types.flow import ControlFlow
|
|
16
13
|
from griptape_nodes.node_library.workflow_registry import WorkflowRegistry
|
|
17
14
|
from griptape_nodes.retained_mode.events.app_events import (
|
|
15
|
+
AppConnectionEstablished,
|
|
18
16
|
AppEndSessionRequest,
|
|
19
17
|
AppEndSessionResultFailure,
|
|
20
18
|
AppEndSessionResultSuccess,
|
|
@@ -40,34 +38,23 @@ from griptape_nodes.retained_mode.events.app_events import (
|
|
|
40
38
|
)
|
|
41
39
|
from griptape_nodes.retained_mode.events.base_events import (
|
|
42
40
|
AppPayload,
|
|
43
|
-
BaseEvent,
|
|
44
41
|
RequestPayload,
|
|
45
42
|
ResultPayload,
|
|
46
43
|
ResultPayloadFailure,
|
|
47
44
|
)
|
|
48
|
-
from griptape_nodes.retained_mode.events.connection_events import (
|
|
49
|
-
CreateConnectionRequest,
|
|
50
|
-
)
|
|
51
45
|
from griptape_nodes.retained_mode.events.flow_events import (
|
|
52
|
-
CreateFlowRequest,
|
|
53
46
|
DeleteFlowRequest,
|
|
54
47
|
)
|
|
55
|
-
from griptape_nodes.retained_mode.events.parameter_events import (
|
|
56
|
-
AddParameterToNodeRequest,
|
|
57
|
-
AlterParameterDetailsRequest,
|
|
58
|
-
)
|
|
59
|
-
from griptape_nodes.retained_mode.utils.engine_identity import EngineIdentity
|
|
60
|
-
from griptape_nodes.retained_mode.utils.session_persistence import SessionPersistence
|
|
61
48
|
from griptape_nodes.utils.metaclasses import SingletonMeta
|
|
62
49
|
|
|
63
50
|
if TYPE_CHECKING:
|
|
64
|
-
from griptape_nodes.exe_types.node_types import BaseNode
|
|
65
51
|
from griptape_nodes.retained_mode.managers.agent_manager import AgentManager
|
|
66
52
|
from griptape_nodes.retained_mode.managers.arbitrary_code_exec_manager import (
|
|
67
53
|
ArbitraryCodeExecManager,
|
|
68
54
|
)
|
|
69
55
|
from griptape_nodes.retained_mode.managers.config_manager import ConfigManager
|
|
70
56
|
from griptape_nodes.retained_mode.managers.context_manager import ContextManager
|
|
57
|
+
from griptape_nodes.retained_mode.managers.engine_identity_manager import EngineIdentityManager
|
|
71
58
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
72
59
|
from griptape_nodes.retained_mode.managers.flow_manager import FlowManager
|
|
73
60
|
from griptape_nodes.retained_mode.managers.library_manager import LibraryManager
|
|
@@ -78,6 +65,7 @@ if TYPE_CHECKING:
|
|
|
78
65
|
)
|
|
79
66
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
80
67
|
from griptape_nodes.retained_mode.managers.secrets_manager import SecretsManager
|
|
68
|
+
from griptape_nodes.retained_mode.managers.session_manager import SessionManager
|
|
81
69
|
from griptape_nodes.retained_mode.managers.static_files_manager import (
|
|
82
70
|
StaticFilesManager,
|
|
83
71
|
)
|
|
@@ -130,6 +118,10 @@ class Version:
|
|
|
130
118
|
"""Equality comparison."""
|
|
131
119
|
return (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch)
|
|
132
120
|
|
|
121
|
+
def __hash__(self) -> int:
|
|
122
|
+
"""Hash function for Version."""
|
|
123
|
+
return hash((self.major, self.minor, self.patch))
|
|
124
|
+
|
|
133
125
|
|
|
134
126
|
class GriptapeNodes(metaclass=SingletonMeta):
|
|
135
127
|
_event_manager: EventManager
|
|
@@ -147,6 +139,8 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
147
139
|
_static_files_manager: StaticFilesManager
|
|
148
140
|
_agent_manager: AgentManager
|
|
149
141
|
_version_compatibility_manager: VersionCompatibilityManager
|
|
142
|
+
_session_manager: SessionManager
|
|
143
|
+
_engine_identity_manager: EngineIdentityManager
|
|
150
144
|
|
|
151
145
|
def __init__(self) -> None:
|
|
152
146
|
from griptape_nodes.retained_mode.managers.agent_manager import AgentManager
|
|
@@ -155,6 +149,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
155
149
|
)
|
|
156
150
|
from griptape_nodes.retained_mode.managers.config_manager import ConfigManager
|
|
157
151
|
from griptape_nodes.retained_mode.managers.context_manager import ContextManager
|
|
152
|
+
from griptape_nodes.retained_mode.managers.engine_identity_manager import EngineIdentityManager
|
|
158
153
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
159
154
|
from griptape_nodes.retained_mode.managers.flow_manager import FlowManager
|
|
160
155
|
from griptape_nodes.retained_mode.managers.library_manager import LibraryManager
|
|
@@ -165,6 +160,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
165
160
|
)
|
|
166
161
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
167
162
|
from griptape_nodes.retained_mode.managers.secrets_manager import SecretsManager
|
|
163
|
+
from griptape_nodes.retained_mode.managers.session_manager import SessionManager
|
|
168
164
|
from griptape_nodes.retained_mode.managers.static_files_manager import (
|
|
169
165
|
StaticFilesManager,
|
|
170
166
|
)
|
|
@@ -178,8 +174,8 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
178
174
|
# Initialize only if our managers haven't been created yet
|
|
179
175
|
if not hasattr(self, "_event_manager"):
|
|
180
176
|
self._event_manager = EventManager()
|
|
181
|
-
self._os_manager = OSManager(self._event_manager)
|
|
182
177
|
self._config_manager = ConfigManager(self._event_manager)
|
|
178
|
+
self._os_manager = OSManager(self._event_manager)
|
|
183
179
|
self._secrets_manager = SecretsManager(self._config_manager, self._event_manager)
|
|
184
180
|
self._object_manager = ObjectManager(self._event_manager)
|
|
185
181
|
self._node_manager = NodeManager(self._event_manager)
|
|
@@ -194,6 +190,8 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
194
190
|
)
|
|
195
191
|
self._agent_manager = AgentManager(self._static_files_manager, self._event_manager)
|
|
196
192
|
self._version_compatibility_manager = VersionCompatibilityManager(self._event_manager)
|
|
193
|
+
self._session_manager = SessionManager(self._event_manager)
|
|
194
|
+
self._engine_identity_manager = EngineIdentityManager(self._event_manager)
|
|
197
195
|
|
|
198
196
|
# Assign handlers now that these are created.
|
|
199
197
|
self._event_manager.assign_manager_to_request_type(
|
|
@@ -203,6 +201,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
203
201
|
AppStartSessionRequest, self.handle_session_start_request
|
|
204
202
|
)
|
|
205
203
|
self._event_manager.assign_manager_to_request_type(AppEndSessionRequest, self.handle_session_end_request)
|
|
204
|
+
self._event_manager.add_listener_to_app_event(AppConnectionEstablished, self.on_app_connection_established)
|
|
206
205
|
self._event_manager.assign_manager_to_request_type(AppGetSessionRequest, self.handle_get_session_request)
|
|
207
206
|
self._event_manager.assign_manager_to_request_type(
|
|
208
207
|
SessionHeartbeatRequest, self.handle_session_heartbeat_request
|
|
@@ -223,16 +222,23 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
223
222
|
return cls()
|
|
224
223
|
|
|
225
224
|
@classmethod
|
|
226
|
-
def handle_request(
|
|
225
|
+
def handle_request(
|
|
226
|
+
cls,
|
|
227
|
+
request: RequestPayload,
|
|
228
|
+
*,
|
|
229
|
+
response_topic: str | None = None,
|
|
230
|
+
request_id: str | None = None,
|
|
231
|
+
) -> ResultPayload:
|
|
227
232
|
event_mgr = GriptapeNodes.EventManager()
|
|
228
233
|
obj_depth_mgr = GriptapeNodes.OperationDepthManager()
|
|
229
234
|
workflow_mgr = GriptapeNodes.WorkflowManager()
|
|
230
|
-
|
|
231
235
|
try:
|
|
232
236
|
return event_mgr.handle_request(
|
|
233
237
|
request=request,
|
|
234
238
|
operation_depth_mgr=obj_depth_mgr,
|
|
235
239
|
workflow_mgr=workflow_mgr,
|
|
240
|
+
response_topic=response_topic,
|
|
241
|
+
request_id=request_id,
|
|
236
242
|
)
|
|
237
243
|
except Exception as e:
|
|
238
244
|
logger.exception(
|
|
@@ -249,7 +255,11 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
249
255
|
|
|
250
256
|
@classmethod
|
|
251
257
|
def get_session_id(cls) -> str | None:
|
|
252
|
-
return
|
|
258
|
+
return GriptapeNodes.SessionManager().get_active_session_id()
|
|
259
|
+
|
|
260
|
+
@classmethod
|
|
261
|
+
def get_engine_id(cls) -> str | None:
|
|
262
|
+
return GriptapeNodes.EngineIdentityManager().get_active_engine_id()
|
|
253
263
|
|
|
254
264
|
@classmethod
|
|
255
265
|
def EventManager(cls) -> EventManager:
|
|
@@ -287,6 +297,10 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
287
297
|
def ConfigManager(cls) -> ConfigManager:
|
|
288
298
|
return GriptapeNodes.get_instance()._config_manager
|
|
289
299
|
|
|
300
|
+
@classmethod
|
|
301
|
+
def OSManager(cls) -> OSManager:
|
|
302
|
+
return GriptapeNodes.get_instance()._os_manager
|
|
303
|
+
|
|
290
304
|
@classmethod
|
|
291
305
|
def SecretsManager(cls) -> SecretsManager:
|
|
292
306
|
return GriptapeNodes.get_instance()._secrets_manager
|
|
@@ -307,6 +321,14 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
307
321
|
def VersionCompatibilityManager(cls) -> VersionCompatibilityManager:
|
|
308
322
|
return GriptapeNodes.get_instance()._version_compatibility_manager
|
|
309
323
|
|
|
324
|
+
@classmethod
|
|
325
|
+
def SessionManager(cls) -> SessionManager:
|
|
326
|
+
return GriptapeNodes.get_instance()._session_manager
|
|
327
|
+
|
|
328
|
+
@classmethod
|
|
329
|
+
def EngineIdentityManager(cls) -> EngineIdentityManager:
|
|
330
|
+
return GriptapeNodes.get_instance()._engine_identity_manager
|
|
331
|
+
|
|
310
332
|
@classmethod
|
|
311
333
|
def clear_data(cls) -> None:
|
|
312
334
|
# Get canvas
|
|
@@ -330,6 +352,27 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
330
352
|
msg = "Failed to successfully delete all objects"
|
|
331
353
|
raise ValueError(msg)
|
|
332
354
|
|
|
355
|
+
def on_app_connection_established(self, _payload: AppConnectionEstablished) -> None:
|
|
356
|
+
from griptape_nodes.app.app import subscribe_to_topic
|
|
357
|
+
|
|
358
|
+
# Subscribe to request topic (engine discovery)
|
|
359
|
+
subscribe_to_topic("request")
|
|
360
|
+
|
|
361
|
+
# Get engine ID and subscribe to engine_id/request
|
|
362
|
+
engine_id = GriptapeNodes.get_engine_id()
|
|
363
|
+
if engine_id:
|
|
364
|
+
subscribe_to_topic(f"engines/{engine_id}/request")
|
|
365
|
+
else:
|
|
366
|
+
logger.warning("Engine ID not available for subscription")
|
|
367
|
+
|
|
368
|
+
# Get session ID and subscribe to session_id/request if available
|
|
369
|
+
session_id = GriptapeNodes.get_session_id()
|
|
370
|
+
if session_id:
|
|
371
|
+
topic = f"sessions/{session_id}/request"
|
|
372
|
+
subscribe_to_topic(topic)
|
|
373
|
+
else:
|
|
374
|
+
logger.info("No session ID available for subscription")
|
|
375
|
+
|
|
333
376
|
def handle_engine_version_request(self, request: GetEngineVersionRequest) -> ResultPayload: # noqa: ARG002
|
|
334
377
|
try:
|
|
335
378
|
engine_ver = Version.from_string(engine_version)
|
|
@@ -348,32 +391,39 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
348
391
|
return GetEngineVersionResultFailure()
|
|
349
392
|
|
|
350
393
|
def handle_session_start_request(self, request: AppStartSessionRequest) -> ResultPayload: # noqa: ARG002
|
|
351
|
-
|
|
394
|
+
from griptape_nodes.app.app import subscribe_to_topic
|
|
395
|
+
|
|
396
|
+
current_session_id = GriptapeNodes.SessionManager().get_active_session_id()
|
|
352
397
|
if current_session_id is None:
|
|
353
398
|
# Client wants a new session
|
|
354
399
|
current_session_id = uuid.uuid4().hex
|
|
355
|
-
|
|
356
|
-
# Persist the session ID to XDG state directory
|
|
357
|
-
SessionPersistence.persist_session(current_session_id)
|
|
400
|
+
GriptapeNodes.SessionManager().save_session(current_session_id)
|
|
358
401
|
details = f"New session '{current_session_id}' started at {datetime.now(tz=UTC)}."
|
|
359
402
|
logger.info(details)
|
|
360
403
|
else:
|
|
361
404
|
details = f"Session '{current_session_id}' already active. Joining..."
|
|
362
405
|
|
|
406
|
+
topic = f"sessions/{current_session_id}/request"
|
|
407
|
+
subscribe_to_topic(topic)
|
|
408
|
+
logger.info("Subscribed to new session topic: %s", topic)
|
|
409
|
+
|
|
363
410
|
return AppStartSessionResultSuccess(current_session_id)
|
|
364
411
|
|
|
365
412
|
def handle_session_end_request(self, _: AppEndSessionRequest) -> ResultPayload:
|
|
413
|
+
from griptape_nodes.app.app import unsubscribe_from_topic
|
|
414
|
+
|
|
366
415
|
try:
|
|
367
|
-
previous_session_id =
|
|
368
|
-
if
|
|
416
|
+
previous_session_id = GriptapeNodes.SessionManager().get_active_session_id()
|
|
417
|
+
if previous_session_id is None:
|
|
369
418
|
details = "No active session to end."
|
|
370
419
|
logger.info(details)
|
|
371
420
|
else:
|
|
372
|
-
details = f"Session '{
|
|
421
|
+
details = f"Session '{previous_session_id}' ended at {datetime.now(tz=UTC)}."
|
|
373
422
|
logger.info(details)
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
423
|
+
GriptapeNodes.SessionManager().clear_saved_session()
|
|
424
|
+
|
|
425
|
+
unsubscribe_topic = f"sessions/{previous_session_id}/request"
|
|
426
|
+
unsubscribe_from_topic(unsubscribe_topic)
|
|
377
427
|
|
|
378
428
|
return AppEndSessionResultSuccess(session_id=previous_session_id)
|
|
379
429
|
except Exception as err:
|
|
@@ -382,7 +432,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
382
432
|
return AppEndSessionResultFailure()
|
|
383
433
|
|
|
384
434
|
def handle_get_session_request(self, _: AppGetSessionRequest) -> ResultPayload:
|
|
385
|
-
return AppGetSessionResultSuccess(session_id=
|
|
435
|
+
return AppGetSessionResultSuccess(session_id=GriptapeNodes.SessionManager().get_active_session_id())
|
|
386
436
|
|
|
387
437
|
def handle_session_heartbeat_request(self, request: SessionHeartbeatRequest) -> ResultPayload: # noqa: ARG002
|
|
388
438
|
"""Handle session heartbeat requests.
|
|
@@ -390,11 +440,12 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
390
440
|
Simply verifies that the session is active and responds with success.
|
|
391
441
|
"""
|
|
392
442
|
try:
|
|
393
|
-
|
|
443
|
+
active_session_id = GriptapeNodes.SessionManager().get_active_session_id()
|
|
444
|
+
if active_session_id is None:
|
|
394
445
|
logger.warning("Session heartbeat received but no active session found")
|
|
395
446
|
return SessionHeartbeatResultFailure()
|
|
396
447
|
|
|
397
|
-
logger.debug("Session heartbeat successful for session: %s",
|
|
448
|
+
logger.debug("Session heartbeat successful for session: %s", active_session_id)
|
|
398
449
|
return SessionHeartbeatResultSuccess()
|
|
399
450
|
except Exception as err:
|
|
400
451
|
logger.error("Failed to handle session heartbeat: %s", err)
|
|
@@ -413,15 +464,15 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
413
464
|
workflow_info = self._get_current_workflow_info()
|
|
414
465
|
|
|
415
466
|
# Get engine name
|
|
416
|
-
engine_name =
|
|
467
|
+
engine_name = GriptapeNodes.EngineIdentityManager().get_engine_name()
|
|
417
468
|
|
|
418
469
|
logger.debug("Engine heartbeat successful")
|
|
419
470
|
return EngineHeartbeatResultSuccess(
|
|
420
471
|
heartbeat_id=request.heartbeat_id,
|
|
421
472
|
engine_version=engine_version,
|
|
422
473
|
engine_name=engine_name,
|
|
423
|
-
engine_id=
|
|
424
|
-
session_id=
|
|
474
|
+
engine_id=GriptapeNodes.EngineIdentityManager().get_active_engine_id(),
|
|
475
|
+
session_id=GriptapeNodes.SessionManager().get_active_session_id(),
|
|
425
476
|
timestamp=datetime.now(tz=UTC).isoformat(),
|
|
426
477
|
**instance_info,
|
|
427
478
|
**workflow_info,
|
|
@@ -433,7 +484,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
433
484
|
def handle_get_engine_name_request(self, request: GetEngineNameRequest) -> ResultPayload: # noqa: ARG002
|
|
434
485
|
"""Handle requests to get the current engine name."""
|
|
435
486
|
try:
|
|
436
|
-
engine_name =
|
|
487
|
+
engine_name = GriptapeNodes.EngineIdentityManager().get_engine_name()
|
|
437
488
|
logger.debug("Retrieved engine name: %s", engine_name)
|
|
438
489
|
return GetEngineNameResultSuccess(engine_name=engine_name)
|
|
439
490
|
except Exception as err:
|
|
@@ -451,7 +502,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
451
502
|
return SetEngineNameResultFailure(error_message=error_message)
|
|
452
503
|
|
|
453
504
|
# Set the new engine name
|
|
454
|
-
|
|
505
|
+
GriptapeNodes.EngineIdentityManager().set_engine_name(request.engine_name.strip())
|
|
455
506
|
logger.info("Engine name set to: %s", request.engine_name.strip())
|
|
456
507
|
return SetEngineNameResultSuccess(engine_name=request.engine_name.strip())
|
|
457
508
|
|
|
@@ -474,45 +525,8 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
474
525
|
# Determine deployment type based on presence of instance environment variables
|
|
475
526
|
instance_info["deployment_type"] = "griptape_hosted" if any(instance_info.values()) else "local"
|
|
476
527
|
|
|
477
|
-
# Get public IP address
|
|
478
|
-
public_ip = self._get_public_ip()
|
|
479
|
-
if public_ip:
|
|
480
|
-
instance_info["public_ip"] = public_ip
|
|
481
|
-
|
|
482
528
|
return instance_info
|
|
483
529
|
|
|
484
|
-
def _get_public_ip(self) -> str | None:
|
|
485
|
-
"""Get the public IP address of this device.
|
|
486
|
-
|
|
487
|
-
Returns the public IP address if available, None otherwise.
|
|
488
|
-
"""
|
|
489
|
-
try:
|
|
490
|
-
# Try multiple services in case one is down
|
|
491
|
-
services = [
|
|
492
|
-
"https://api.ipify.org",
|
|
493
|
-
"https://ipinfo.io/ip",
|
|
494
|
-
"https://icanhazip.com",
|
|
495
|
-
]
|
|
496
|
-
|
|
497
|
-
for service in services:
|
|
498
|
-
try:
|
|
499
|
-
with httpx.Client(timeout=5.0) as client:
|
|
500
|
-
response = client.get(service)
|
|
501
|
-
response.raise_for_status()
|
|
502
|
-
public_ip = response.text.strip()
|
|
503
|
-
if public_ip:
|
|
504
|
-
logger.debug("Retrieved public IP from %s: %s", service, public_ip)
|
|
505
|
-
return public_ip
|
|
506
|
-
except Exception as err:
|
|
507
|
-
logger.debug("Failed to get public IP from %s: %s", service, err)
|
|
508
|
-
continue
|
|
509
|
-
logger.warning("Unable to retrieve public IP from any service")
|
|
510
|
-
except Exception as err:
|
|
511
|
-
logger.warning("Failed to get public IP: %s", err)
|
|
512
|
-
return None
|
|
513
|
-
else:
|
|
514
|
-
return None
|
|
515
|
-
|
|
516
530
|
def _get_current_workflow_info(self) -> dict[str, Any]:
|
|
517
531
|
"""Get information about the currently loaded workflow.
|
|
518
532
|
|
|
@@ -543,291 +557,3 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
543
557
|
logger.warning("Failed to get current workflow info: %s", err)
|
|
544
558
|
|
|
545
559
|
return workflow_info
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
def create_flows_in_order(flow_name: str, flow_manager: FlowManager, created_flows: list, file: IO) -> list | None:
|
|
549
|
-
"""Creates flows in the correct order based on their dependencies."""
|
|
550
|
-
# If this flow is already created, we can return
|
|
551
|
-
if flow_name in created_flows:
|
|
552
|
-
return None
|
|
553
|
-
|
|
554
|
-
# Get the parent of this flow
|
|
555
|
-
parent = flow_manager.get_parent_flow(flow_name)
|
|
556
|
-
|
|
557
|
-
# If there's a parent, create it first
|
|
558
|
-
if parent:
|
|
559
|
-
create_flows_in_order(parent, flow_manager, created_flows, file)
|
|
560
|
-
|
|
561
|
-
# Now create this flow (only if not already created)
|
|
562
|
-
if flow_name not in created_flows:
|
|
563
|
-
# Here you would actually send the request and handle response
|
|
564
|
-
creation_request = CreateFlowRequest(flow_name=flow_name, parent_flow_name=parent)
|
|
565
|
-
code_string = f"GriptapeNodes.handle_request({creation_request})"
|
|
566
|
-
file.write(code_string + "\n")
|
|
567
|
-
created_flows.append(flow_name)
|
|
568
|
-
|
|
569
|
-
return created_flows
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
def handle_flow_saving(file: TextIO, obj_manager: ObjectManager, created_flows: list) -> str:
|
|
573
|
-
"""Handles the creation and saving of flows."""
|
|
574
|
-
flow_manager = GriptapeNodes.FlowManager()
|
|
575
|
-
connection_request_workflows = ""
|
|
576
|
-
for flow_name, flow in obj_manager.get_filtered_subset(type=ControlFlow).items():
|
|
577
|
-
create_flows_in_order(flow_name, flow_manager, created_flows, file)
|
|
578
|
-
# While creating flows - let's create all of our connections
|
|
579
|
-
for connection in flow.connections.connections.values():
|
|
580
|
-
creation_request = CreateConnectionRequest(
|
|
581
|
-
source_node_name=connection.source_node.name,
|
|
582
|
-
source_parameter_name=connection.source_parameter.name,
|
|
583
|
-
target_node_name=connection.target_node.name,
|
|
584
|
-
target_parameter_name=connection.target_parameter.name,
|
|
585
|
-
initial_setup=True,
|
|
586
|
-
)
|
|
587
|
-
code_string = f"GriptapeNodes.handle_request({creation_request})"
|
|
588
|
-
connection_request_workflows += code_string + "\n"
|
|
589
|
-
return connection_request_workflows
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
def handle_parameter_creation_saving(node: BaseNode, values_created: dict) -> tuple[str, bool]:
|
|
593
|
-
"""Handles the creation and saving of parameters for a node."""
|
|
594
|
-
parameter_details = ""
|
|
595
|
-
saved_properly = True
|
|
596
|
-
# Get all parameters, even ones that aren't direct children.
|
|
597
|
-
for parameter in node.root_ui_element.find_elements_by_type(BaseNodeElement):
|
|
598
|
-
if isinstance(parameter, (Parameter, ParameterGroup, ParameterContainer)):
|
|
599
|
-
param_dict = parameter.to_dict()
|
|
600
|
-
# Create the parameter, or alter it on the existing node
|
|
601
|
-
if isinstance(parameter, Parameter) and parameter.user_defined:
|
|
602
|
-
param_dict["node_name"] = node.name
|
|
603
|
-
param_dict["initial_setup"] = True
|
|
604
|
-
creation_request = AddParameterToNodeRequest.create(**param_dict)
|
|
605
|
-
code_string = f"GriptapeNodes.handle_request({creation_request})\n"
|
|
606
|
-
parameter_details += code_string
|
|
607
|
-
else:
|
|
608
|
-
base_node_obj = type(node)(name="test")
|
|
609
|
-
diff = manage_alter_details(parameter, base_node_obj)
|
|
610
|
-
relevant = False
|
|
611
|
-
for key in diff:
|
|
612
|
-
if key in AlterParameterDetailsRequest.relevant_parameters():
|
|
613
|
-
relevant = True
|
|
614
|
-
break
|
|
615
|
-
if relevant:
|
|
616
|
-
diff["node_name"] = node.name
|
|
617
|
-
diff["parameter_name"] = parameter.name
|
|
618
|
-
diff["initial_setup"] = True
|
|
619
|
-
creation_request = AlterParameterDetailsRequest.create(**diff)
|
|
620
|
-
code_string = f"GriptapeNodes.handle_request({creation_request})\n"
|
|
621
|
-
parameter_details += code_string
|
|
622
|
-
if not isinstance(parameter, ParameterGroup) and (
|
|
623
|
-
parameter.name in node.parameter_values or parameter.name in node.parameter_output_values
|
|
624
|
-
):
|
|
625
|
-
# SetParameterValueRequest event
|
|
626
|
-
code_string = handle_parameter_value_saving(parameter, node, values_created)
|
|
627
|
-
if code_string:
|
|
628
|
-
code_string = code_string + "\n"
|
|
629
|
-
parameter_details += code_string
|
|
630
|
-
else:
|
|
631
|
-
saved_properly = False
|
|
632
|
-
return parameter_details, saved_properly
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
def handle_parameter_value_saving(parameter: Parameter, node: BaseNode, values_created: dict) -> str | None:
|
|
636
|
-
"""Generates code to save a parameter value for a node in a Griptape workflow.
|
|
637
|
-
|
|
638
|
-
This function handles the process of creating code that will reconstruct and set
|
|
639
|
-
parameter values for nodes. It performs the following steps:
|
|
640
|
-
1. Retrieves the parameter value from the node's parameter values or output values
|
|
641
|
-
2. Checks if the value has already been created in the generated code
|
|
642
|
-
3. If not, generates code to reconstruct the value
|
|
643
|
-
4. Creates a SetParameterValueRequest to apply the value to the node
|
|
644
|
-
|
|
645
|
-
Args:
|
|
646
|
-
parameter (Parameter): The parameter object containing metadata
|
|
647
|
-
node (BaseNode): The node object that contains the parameter
|
|
648
|
-
values_created (dict): Dictionary mapping value identifiers to variable names
|
|
649
|
-
that have already been created in the code
|
|
650
|
-
|
|
651
|
-
Returns:
|
|
652
|
-
str | None: Python code as a string that will reconstruct and set the parameter
|
|
653
|
-
value when executed. Returns None if the parameter has no value or
|
|
654
|
-
if the value cannot be properly represented.
|
|
655
|
-
|
|
656
|
-
Notes:
|
|
657
|
-
- Parameter output values take precedence over regular parameter values
|
|
658
|
-
- For values that can be hashed, the value itself is used as the key in values_created
|
|
659
|
-
- For unhashable values, the object's id is used as the key
|
|
660
|
-
- The function will reuse already created values to avoid duplication
|
|
661
|
-
"""
|
|
662
|
-
value = None
|
|
663
|
-
is_output = False
|
|
664
|
-
if parameter.name in node.parameter_values:
|
|
665
|
-
value = node.get_parameter_value(parameter.name)
|
|
666
|
-
# Output values are more important
|
|
667
|
-
if parameter.name in node.parameter_output_values:
|
|
668
|
-
value = node.parameter_output_values[parameter.name]
|
|
669
|
-
is_output = True
|
|
670
|
-
if value is not None:
|
|
671
|
-
try:
|
|
672
|
-
hash(value)
|
|
673
|
-
value_id = value
|
|
674
|
-
except TypeError:
|
|
675
|
-
value_id = id(value)
|
|
676
|
-
if value_id in values_created:
|
|
677
|
-
var_name = values_created[value_id]
|
|
678
|
-
# We've already created this object. we're all good.
|
|
679
|
-
return f"GriptapeNodes.handle_request(SetParameterValueRequest(parameter_name='{parameter.name}', node_name='{node.name}', value={var_name}, initial_setup=True, is_output={is_output}))"
|
|
680
|
-
# Set it up as a object in the code
|
|
681
|
-
imports = []
|
|
682
|
-
var_name = f"{node.name}_{parameter.name}_value"
|
|
683
|
-
values_created[value_id] = var_name
|
|
684
|
-
reconstruction_code = _convert_value_to_str_representation(var_name, value, imports)
|
|
685
|
-
# If it doesn't have a custom __str__, convert to dict if possible
|
|
686
|
-
if reconstruction_code != "":
|
|
687
|
-
# Add the request handling code
|
|
688
|
-
final_code = (
|
|
689
|
-
reconstruction_code
|
|
690
|
-
+ f"GriptapeNodes.handle_request(SetParameterValueRequest(parameter_name='{parameter.name}', node_name='{node.name}', value={var_name}, initial_setup=True, is_output={is_output}))"
|
|
691
|
-
)
|
|
692
|
-
# Combine imports and code
|
|
693
|
-
import_statements = ""
|
|
694
|
-
if imports:
|
|
695
|
-
import_statements = "\n".join(list(set(imports))) + "\n\n" # Remove duplicates with set()
|
|
696
|
-
return import_statements + final_code
|
|
697
|
-
return None
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
def _convert_value_to_str_representation(var_name: str, value: Any, imports: list) -> str:
|
|
701
|
-
"""Converts a Python value to its string representation as executable code.
|
|
702
|
-
|
|
703
|
-
This function generates Python code that can recreate the given value
|
|
704
|
-
when executed. It handles different types of values with specific strategies:
|
|
705
|
-
- Objects with a 'to_dict' method: Uses _create_object_in_file for reconstruction
|
|
706
|
-
- Basic Python types: Uses their repr representation
|
|
707
|
-
- If not representable: Returns empty string
|
|
708
|
-
|
|
709
|
-
Args:
|
|
710
|
-
var_name (str): The variable name to assign the value to in the generated code
|
|
711
|
-
value (Any): The Python value to convert to code
|
|
712
|
-
imports (list): List to which any required import statements will be appended
|
|
713
|
-
|
|
714
|
-
Returns:
|
|
715
|
-
str: Python code as a string that will reconstruct the value when executed.
|
|
716
|
-
Returns empty string if the value cannot be properly represented.
|
|
717
|
-
"""
|
|
718
|
-
reconstruction_code = ""
|
|
719
|
-
# If it doesn't have a custom __str__, convert to dict if possible
|
|
720
|
-
if hasattr(value, "to_dict") and callable(value.to_dict):
|
|
721
|
-
# For objects with to_dict method
|
|
722
|
-
reconstruction_code = _create_object_in_file(value, var_name, imports)
|
|
723
|
-
return reconstruction_code
|
|
724
|
-
if isinstance(value, (int, float, str, bool)) or value is None:
|
|
725
|
-
# For basic types, use repr to create a literal
|
|
726
|
-
return f"{var_name} = {value!r}\n"
|
|
727
|
-
if isinstance(value, (list, dict, tuple, set)):
|
|
728
|
-
reconstruction_code = _convert_container_to_str_representation(var_name, value, imports, type(value))
|
|
729
|
-
return reconstruction_code
|
|
730
|
-
return ""
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
def _convert_container_to_str_representation(var_name: str, value: Any, imports: list, value_type: type) -> str:
|
|
734
|
-
"""Creates code to reconstruct a container type (list, dict, tuple, set) with its elements.
|
|
735
|
-
|
|
736
|
-
Args:
|
|
737
|
-
var_name (str): The variable name to assign the container to
|
|
738
|
-
value (Any): The container value to convert to code
|
|
739
|
-
imports (list): List to which any required import statements will be appended
|
|
740
|
-
value_type (type): The type of container (list, dict, tuple, or set)
|
|
741
|
-
|
|
742
|
-
Returns:
|
|
743
|
-
str: Python code as a string that will reconstruct the container
|
|
744
|
-
"""
|
|
745
|
-
# Get the initialization brackets from an empty container
|
|
746
|
-
empty_container = value_type()
|
|
747
|
-
init_brackets = repr(empty_container)
|
|
748
|
-
# Initialize the container
|
|
749
|
-
code = f"{var_name} = {init_brackets}\n"
|
|
750
|
-
temp_var_base = f"{var_name}_item"
|
|
751
|
-
if value_type is dict:
|
|
752
|
-
# Process dictionary items
|
|
753
|
-
for i, (k, v) in enumerate(value.items()):
|
|
754
|
-
temp_var = f"{temp_var_base}_{i}"
|
|
755
|
-
# Convert the value to code
|
|
756
|
-
value_code = _convert_value_to_str_representation(temp_var, v, imports)
|
|
757
|
-
if value_code:
|
|
758
|
-
code += value_code
|
|
759
|
-
code += f"{var_name}[{k!r}] = {temp_var}\n"
|
|
760
|
-
else:
|
|
761
|
-
code += f"{var_name}[{k!r}] = {v!r}\n"
|
|
762
|
-
else:
|
|
763
|
-
# Process sequence items (list, tuple, set)
|
|
764
|
-
# For immutable types like tuple and set, we need to build a list first
|
|
765
|
-
for i, item in enumerate(value):
|
|
766
|
-
temp_var = f"{temp_var_base}_{i}"
|
|
767
|
-
# Convert the item to code
|
|
768
|
-
item_code = _convert_value_to_str_representation(temp_var, item, imports)
|
|
769
|
-
if item_code != "":
|
|
770
|
-
code += item_code
|
|
771
|
-
code += f"{var_name}.append({temp_var})\n"
|
|
772
|
-
else:
|
|
773
|
-
code += f"{var_name}.append({item!r})\n"
|
|
774
|
-
# Convert the list to the final type if needed
|
|
775
|
-
if value_type in (tuple, set):
|
|
776
|
-
code += f"{var_name} = {value_type.__name__}({var_name})\n"
|
|
777
|
-
return code
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
def _create_object_in_file(value: Any, var_name: str, imports: list) -> str:
|
|
781
|
-
"""Creates Python code to reconstruct an object from its dictionary representation and adds necessary import statements.
|
|
782
|
-
|
|
783
|
-
Args:
|
|
784
|
-
value (Any): The object to be serialized into Python code
|
|
785
|
-
var_name (str): The name of the variable to assign the object to in the generated code
|
|
786
|
-
imports (list): List to which import statements will be appended
|
|
787
|
-
|
|
788
|
-
Returns:
|
|
789
|
-
str: Python code string that reconstructs the object when executed
|
|
790
|
-
Returns empty string if object cannot be properly reconstructed
|
|
791
|
-
|
|
792
|
-
Notes:
|
|
793
|
-
- The function assumes the object has a 'to_dict()' method to serialize it. It is only called if the object does have that method.
|
|
794
|
-
- For class instances, it will add appropriate import statements to 'imports'
|
|
795
|
-
- The generated code will create a dictionary representation first, then
|
|
796
|
-
reconstruct the object using a 'from_dict' class method
|
|
797
|
-
"""
|
|
798
|
-
obj_dict = value.to_dict()
|
|
799
|
-
reconstruction_code = f"{var_name} = {obj_dict!r}\n"
|
|
800
|
-
# If we know the class, we can reconstruct it and add import
|
|
801
|
-
if hasattr(value, "__class__"):
|
|
802
|
-
class_name = value.__class__.__name__
|
|
803
|
-
module_name = value.__class__.__module__
|
|
804
|
-
if module_name != "builtins":
|
|
805
|
-
imports.append(f"from {module_name} import {class_name}")
|
|
806
|
-
reconstruction_code += f"{var_name} = {class_name}.from_dict({var_name})\n"
|
|
807
|
-
return reconstruction_code
|
|
808
|
-
return ""
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
def manage_alter_details(parameter: Parameter | ParameterGroup, base_node_obj: BaseNode) -> dict:
|
|
812
|
-
"""Alters the details of a parameter based on the base node object."""
|
|
813
|
-
if isinstance(parameter, Parameter):
|
|
814
|
-
base_param = base_node_obj.get_parameter_by_name(parameter.name)
|
|
815
|
-
if base_param is not None:
|
|
816
|
-
diff = base_param.equals(parameter)
|
|
817
|
-
else:
|
|
818
|
-
return vars(parameter)
|
|
819
|
-
else:
|
|
820
|
-
base_param_group = base_node_obj.get_group_by_name_or_element_id(parameter.name)
|
|
821
|
-
if base_param_group is not None:
|
|
822
|
-
diff = base_param_group.equals(parameter)
|
|
823
|
-
else:
|
|
824
|
-
return vars(parameter)
|
|
825
|
-
return diff
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
def __getattr__(name: str) -> logging.Logger:
|
|
829
|
-
"""Convenience function so that node authors only need to write 'logger.debug()'."""
|
|
830
|
-
if name == "logger":
|
|
831
|
-
return logger
|
|
832
|
-
msg = f"module '{__name__}' has no attribute '{name}'"
|
|
833
|
-
raise AttributeError(msg)
|
|
File without changes
|