griptape-nodes 0.40.0__py3-none-any.whl → 0.42.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/app/__init__.py +1 -5
- griptape_nodes/app/app.py +12 -9
- griptape_nodes/app/app_sessions.py +132 -36
- griptape_nodes/app/watch.py +3 -1
- griptape_nodes/drivers/storage/local_storage_driver.py +3 -2
- griptape_nodes/exe_types/flow.py +68 -368
- griptape_nodes/machines/control_flow.py +16 -13
- griptape_nodes/machines/node_resolution.py +16 -14
- griptape_nodes/node_library/workflow_registry.py +2 -2
- griptape_nodes/retained_mode/events/agent_events.py +70 -8
- griptape_nodes/retained_mode/events/app_events.py +132 -11
- griptape_nodes/retained_mode/events/arbitrary_python_events.py +23 -0
- griptape_nodes/retained_mode/events/base_events.py +7 -25
- 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/library_events.py +193 -15
- griptape_nodes/retained_mode/events/logger_events.py +11 -0
- griptape_nodes/retained_mode/events/node_events.py +243 -22
- griptape_nodes/retained_mode/events/object_events.py +40 -4
- griptape_nodes/retained_mode/events/os_events.py +13 -2
- griptape_nodes/retained_mode/events/parameter_events.py +212 -8
- 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 +46 -323
- griptape_nodes/retained_mode/managers/agent_manager.py +1 -1
- 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 +749 -64
- griptape_nodes/retained_mode/managers/library_manager.py +112 -2
- griptape_nodes/retained_mode/managers/node_manager.py +35 -32
- griptape_nodes/retained_mode/managers/object_manager.py +11 -3
- griptape_nodes/retained_mode/managers/os_manager.py +70 -1
- 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/workflow_manager.py +523 -454
- griptape_nodes/retained_mode/retained_mode.py +44 -0
- griptape_nodes/retained_mode/utils/engine_identity.py +141 -27
- {griptape_nodes-0.40.0.dist-info → griptape_nodes-0.42.0.dist-info}/METADATA +2 -2
- {griptape_nodes-0.40.0.dist-info → griptape_nodes-0.42.0.dist-info}/RECORD +48 -47
- griptape_nodes/retained_mode/utils/session_persistence.py +0 -105
- {griptape_nodes-0.40.0.dist-info → griptape_nodes-0.42.0.dist-info}/WHEEL +0 -0
- {griptape_nodes-0.40.0.dist-info → griptape_nodes-0.42.0.dist-info}/entry_points.txt +0 -0
- {griptape_nodes-0.40.0.dist-info → griptape_nodes-0.42.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -7,11 +7,10 @@ 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
12
|
import httpx
|
|
13
13
|
|
|
14
|
-
from griptape_nodes.exe_types.core_types import BaseNodeElement, Parameter, ParameterContainer, ParameterGroup
|
|
15
14
|
from griptape_nodes.exe_types.flow import ControlFlow
|
|
16
15
|
from griptape_nodes.node_library.workflow_registry import WorkflowRegistry
|
|
17
16
|
from griptape_nodes.retained_mode.events.app_events import (
|
|
@@ -40,34 +39,23 @@ from griptape_nodes.retained_mode.events.app_events import (
|
|
|
40
39
|
)
|
|
41
40
|
from griptape_nodes.retained_mode.events.base_events import (
|
|
42
41
|
AppPayload,
|
|
43
|
-
BaseEvent,
|
|
44
42
|
RequestPayload,
|
|
45
43
|
ResultPayload,
|
|
46
44
|
ResultPayloadFailure,
|
|
47
45
|
)
|
|
48
|
-
from griptape_nodes.retained_mode.events.connection_events import (
|
|
49
|
-
CreateConnectionRequest,
|
|
50
|
-
)
|
|
51
46
|
from griptape_nodes.retained_mode.events.flow_events import (
|
|
52
|
-
CreateFlowRequest,
|
|
53
47
|
DeleteFlowRequest,
|
|
54
48
|
)
|
|
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
49
|
from griptape_nodes.utils.metaclasses import SingletonMeta
|
|
62
50
|
|
|
63
51
|
if TYPE_CHECKING:
|
|
64
|
-
from griptape_nodes.exe_types.node_types import BaseNode
|
|
65
52
|
from griptape_nodes.retained_mode.managers.agent_manager import AgentManager
|
|
66
53
|
from griptape_nodes.retained_mode.managers.arbitrary_code_exec_manager import (
|
|
67
54
|
ArbitraryCodeExecManager,
|
|
68
55
|
)
|
|
69
56
|
from griptape_nodes.retained_mode.managers.config_manager import ConfigManager
|
|
70
57
|
from griptape_nodes.retained_mode.managers.context_manager import ContextManager
|
|
58
|
+
from griptape_nodes.retained_mode.managers.engine_identity_manager import EngineIdentityManager
|
|
71
59
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
72
60
|
from griptape_nodes.retained_mode.managers.flow_manager import FlowManager
|
|
73
61
|
from griptape_nodes.retained_mode.managers.library_manager import LibraryManager
|
|
@@ -78,6 +66,7 @@ if TYPE_CHECKING:
|
|
|
78
66
|
)
|
|
79
67
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
80
68
|
from griptape_nodes.retained_mode.managers.secrets_manager import SecretsManager
|
|
69
|
+
from griptape_nodes.retained_mode.managers.session_manager import SessionManager
|
|
81
70
|
from griptape_nodes.retained_mode.managers.static_files_manager import (
|
|
82
71
|
StaticFilesManager,
|
|
83
72
|
)
|
|
@@ -147,6 +136,8 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
147
136
|
_static_files_manager: StaticFilesManager
|
|
148
137
|
_agent_manager: AgentManager
|
|
149
138
|
_version_compatibility_manager: VersionCompatibilityManager
|
|
139
|
+
_session_manager: SessionManager
|
|
140
|
+
_engine_identity_manager: EngineIdentityManager
|
|
150
141
|
|
|
151
142
|
def __init__(self) -> None:
|
|
152
143
|
from griptape_nodes.retained_mode.managers.agent_manager import AgentManager
|
|
@@ -155,6 +146,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
155
146
|
)
|
|
156
147
|
from griptape_nodes.retained_mode.managers.config_manager import ConfigManager
|
|
157
148
|
from griptape_nodes.retained_mode.managers.context_manager import ContextManager
|
|
149
|
+
from griptape_nodes.retained_mode.managers.engine_identity_manager import EngineIdentityManager
|
|
158
150
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
159
151
|
from griptape_nodes.retained_mode.managers.flow_manager import FlowManager
|
|
160
152
|
from griptape_nodes.retained_mode.managers.library_manager import LibraryManager
|
|
@@ -165,6 +157,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
165
157
|
)
|
|
166
158
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
167
159
|
from griptape_nodes.retained_mode.managers.secrets_manager import SecretsManager
|
|
160
|
+
from griptape_nodes.retained_mode.managers.session_manager import SessionManager
|
|
168
161
|
from griptape_nodes.retained_mode.managers.static_files_manager import (
|
|
169
162
|
StaticFilesManager,
|
|
170
163
|
)
|
|
@@ -194,6 +187,8 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
194
187
|
)
|
|
195
188
|
self._agent_manager = AgentManager(self._static_files_manager, self._event_manager)
|
|
196
189
|
self._version_compatibility_manager = VersionCompatibilityManager(self._event_manager)
|
|
190
|
+
self._session_manager = SessionManager(self._event_manager)
|
|
191
|
+
self._engine_identity_manager = EngineIdentityManager(self._event_manager)
|
|
197
192
|
|
|
198
193
|
# Assign handlers now that these are created.
|
|
199
194
|
self._event_manager.assign_manager_to_request_type(
|
|
@@ -223,16 +218,23 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
223
218
|
return cls()
|
|
224
219
|
|
|
225
220
|
@classmethod
|
|
226
|
-
def handle_request(
|
|
221
|
+
def handle_request(
|
|
222
|
+
cls,
|
|
223
|
+
request: RequestPayload,
|
|
224
|
+
*,
|
|
225
|
+
response_topic: str | None = None,
|
|
226
|
+
request_id: str | None = None,
|
|
227
|
+
) -> ResultPayload:
|
|
227
228
|
event_mgr = GriptapeNodes.EventManager()
|
|
228
229
|
obj_depth_mgr = GriptapeNodes.OperationDepthManager()
|
|
229
230
|
workflow_mgr = GriptapeNodes.WorkflowManager()
|
|
230
|
-
|
|
231
231
|
try:
|
|
232
232
|
return event_mgr.handle_request(
|
|
233
233
|
request=request,
|
|
234
234
|
operation_depth_mgr=obj_depth_mgr,
|
|
235
235
|
workflow_mgr=workflow_mgr,
|
|
236
|
+
response_topic=response_topic,
|
|
237
|
+
request_id=request_id,
|
|
236
238
|
)
|
|
237
239
|
except Exception as e:
|
|
238
240
|
logger.exception(
|
|
@@ -249,7 +251,11 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
249
251
|
|
|
250
252
|
@classmethod
|
|
251
253
|
def get_session_id(cls) -> str | None:
|
|
252
|
-
return
|
|
254
|
+
return GriptapeNodes.SessionManager().get_active_session_id()
|
|
255
|
+
|
|
256
|
+
@classmethod
|
|
257
|
+
def get_engine_id(cls) -> str | None:
|
|
258
|
+
return GriptapeNodes.EngineIdentityManager().get_active_engine_id()
|
|
253
259
|
|
|
254
260
|
@classmethod
|
|
255
261
|
def EventManager(cls) -> EventManager:
|
|
@@ -307,6 +313,14 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
307
313
|
def VersionCompatibilityManager(cls) -> VersionCompatibilityManager:
|
|
308
314
|
return GriptapeNodes.get_instance()._version_compatibility_manager
|
|
309
315
|
|
|
316
|
+
@classmethod
|
|
317
|
+
def SessionManager(cls) -> SessionManager:
|
|
318
|
+
return GriptapeNodes.get_instance()._session_manager
|
|
319
|
+
|
|
320
|
+
@classmethod
|
|
321
|
+
def EngineIdentityManager(cls) -> EngineIdentityManager:
|
|
322
|
+
return GriptapeNodes.get_instance()._engine_identity_manager
|
|
323
|
+
|
|
310
324
|
@classmethod
|
|
311
325
|
def clear_data(cls) -> None:
|
|
312
326
|
# Get canvas
|
|
@@ -348,13 +362,11 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
348
362
|
return GetEngineVersionResultFailure()
|
|
349
363
|
|
|
350
364
|
def handle_session_start_request(self, request: AppStartSessionRequest) -> ResultPayload: # noqa: ARG002
|
|
351
|
-
current_session_id =
|
|
365
|
+
current_session_id = GriptapeNodes.SessionManager().get_active_session_id()
|
|
352
366
|
if current_session_id is None:
|
|
353
367
|
# Client wants a new session
|
|
354
368
|
current_session_id = uuid.uuid4().hex
|
|
355
|
-
|
|
356
|
-
# Persist the session ID to XDG state directory
|
|
357
|
-
SessionPersistence.persist_session(current_session_id)
|
|
369
|
+
GriptapeNodes.SessionManager().save_session(current_session_id)
|
|
358
370
|
details = f"New session '{current_session_id}' started at {datetime.now(tz=UTC)}."
|
|
359
371
|
logger.info(details)
|
|
360
372
|
else:
|
|
@@ -364,16 +376,14 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
364
376
|
|
|
365
377
|
def handle_session_end_request(self, _: AppEndSessionRequest) -> ResultPayload:
|
|
366
378
|
try:
|
|
367
|
-
previous_session_id =
|
|
368
|
-
if
|
|
379
|
+
previous_session_id = GriptapeNodes.SessionManager().get_active_session_id()
|
|
380
|
+
if previous_session_id is None:
|
|
369
381
|
details = "No active session to end."
|
|
370
382
|
logger.info(details)
|
|
371
383
|
else:
|
|
372
|
-
details = f"Session '{
|
|
384
|
+
details = f"Session '{previous_session_id}' ended at {datetime.now(tz=UTC)}."
|
|
373
385
|
logger.info(details)
|
|
374
|
-
|
|
375
|
-
# Clear the persisted session ID from XDG state directory
|
|
376
|
-
SessionPersistence.clear_persisted_session()
|
|
386
|
+
GriptapeNodes.SessionManager().clear_saved_session()
|
|
377
387
|
|
|
378
388
|
return AppEndSessionResultSuccess(session_id=previous_session_id)
|
|
379
389
|
except Exception as err:
|
|
@@ -382,7 +392,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
382
392
|
return AppEndSessionResultFailure()
|
|
383
393
|
|
|
384
394
|
def handle_get_session_request(self, _: AppGetSessionRequest) -> ResultPayload:
|
|
385
|
-
return AppGetSessionResultSuccess(session_id=
|
|
395
|
+
return AppGetSessionResultSuccess(session_id=GriptapeNodes.SessionManager().get_active_session_id())
|
|
386
396
|
|
|
387
397
|
def handle_session_heartbeat_request(self, request: SessionHeartbeatRequest) -> ResultPayload: # noqa: ARG002
|
|
388
398
|
"""Handle session heartbeat requests.
|
|
@@ -390,11 +400,12 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
390
400
|
Simply verifies that the session is active and responds with success.
|
|
391
401
|
"""
|
|
392
402
|
try:
|
|
393
|
-
|
|
403
|
+
active_session_id = GriptapeNodes.SessionManager().get_active_session_id()
|
|
404
|
+
if active_session_id is None:
|
|
394
405
|
logger.warning("Session heartbeat received but no active session found")
|
|
395
406
|
return SessionHeartbeatResultFailure()
|
|
396
407
|
|
|
397
|
-
logger.debug("Session heartbeat successful for session: %s",
|
|
408
|
+
logger.debug("Session heartbeat successful for session: %s", active_session_id)
|
|
398
409
|
return SessionHeartbeatResultSuccess()
|
|
399
410
|
except Exception as err:
|
|
400
411
|
logger.error("Failed to handle session heartbeat: %s", err)
|
|
@@ -413,15 +424,15 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
413
424
|
workflow_info = self._get_current_workflow_info()
|
|
414
425
|
|
|
415
426
|
# Get engine name
|
|
416
|
-
engine_name =
|
|
427
|
+
engine_name = GriptapeNodes.EngineIdentityManager().get_engine_name()
|
|
417
428
|
|
|
418
429
|
logger.debug("Engine heartbeat successful")
|
|
419
430
|
return EngineHeartbeatResultSuccess(
|
|
420
431
|
heartbeat_id=request.heartbeat_id,
|
|
421
432
|
engine_version=engine_version,
|
|
422
433
|
engine_name=engine_name,
|
|
423
|
-
engine_id=
|
|
424
|
-
session_id=
|
|
434
|
+
engine_id=GriptapeNodes.EngineIdentityManager().get_active_engine_id(),
|
|
435
|
+
session_id=GriptapeNodes.SessionManager().get_active_session_id(),
|
|
425
436
|
timestamp=datetime.now(tz=UTC).isoformat(),
|
|
426
437
|
**instance_info,
|
|
427
438
|
**workflow_info,
|
|
@@ -433,7 +444,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
433
444
|
def handle_get_engine_name_request(self, request: GetEngineNameRequest) -> ResultPayload: # noqa: ARG002
|
|
434
445
|
"""Handle requests to get the current engine name."""
|
|
435
446
|
try:
|
|
436
|
-
engine_name =
|
|
447
|
+
engine_name = GriptapeNodes.EngineIdentityManager().get_engine_name()
|
|
437
448
|
logger.debug("Retrieved engine name: %s", engine_name)
|
|
438
449
|
return GetEngineNameResultSuccess(engine_name=engine_name)
|
|
439
450
|
except Exception as err:
|
|
@@ -451,7 +462,7 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
451
462
|
return SetEngineNameResultFailure(error_message=error_message)
|
|
452
463
|
|
|
453
464
|
# Set the new engine name
|
|
454
|
-
|
|
465
|
+
GriptapeNodes.EngineIdentityManager().set_engine_name(request.engine_name.strip())
|
|
455
466
|
logger.info("Engine name set to: %s", request.engine_name.strip())
|
|
456
467
|
return SetEngineNameResultSuccess(engine_name=request.engine_name.strip())
|
|
457
468
|
|
|
@@ -543,291 +554,3 @@ class GriptapeNodes(metaclass=SingletonMeta):
|
|
|
543
554
|
logger.warning("Failed to get current workflow info: %s", err)
|
|
544
555
|
|
|
545
556
|
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)
|
|
@@ -109,7 +109,7 @@ class AgentManager:
|
|
|
109
109
|
msg = f"Secret '{API_KEY_ENV_VAR}' not found"
|
|
110
110
|
raise ValueError(msg)
|
|
111
111
|
return NodesPromptImageGenerationTool(
|
|
112
|
-
image_generation_driver=GriptapeCloudImageGenerationDriver(api_key=api_key, model="
|
|
112
|
+
image_generation_driver=GriptapeCloudImageGenerationDriver(api_key=api_key, model="gpt-image-1"),
|
|
113
113
|
static_files_manager=self.static_files_manager,
|
|
114
114
|
)
|
|
115
115
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""Manages engine identity state.
|
|
2
|
+
|
|
3
|
+
Centralizes engine identity management, providing a consistent interface for
|
|
4
|
+
engine ID and name operations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from griptape_nodes.retained_mode.events.base_events import BaseEvent
|
|
11
|
+
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
12
|
+
from griptape_nodes.retained_mode.utils.engine_identity import EngineIdentity
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger("griptape_nodes")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class EngineIdentityManager:
|
|
18
|
+
"""Manages engine identity and active engine state."""
|
|
19
|
+
|
|
20
|
+
_active_engine_id: str | None = None
|
|
21
|
+
|
|
22
|
+
def __init__(self, event_manager: EventManager | None = None) -> None:
|
|
23
|
+
"""Initialize the EngineIdentityManager.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
event_manager: The EventManager instance to use for event handling.
|
|
27
|
+
"""
|
|
28
|
+
if event_manager is not None:
|
|
29
|
+
# Register event handlers here when engine events are defined
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def get_active_engine_id(cls) -> str | None:
|
|
34
|
+
"""Get the active engine ID.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
str | None: The active engine ID or None if not set
|
|
38
|
+
"""
|
|
39
|
+
return cls._active_engine_id
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def set_active_engine_id(cls, engine_id: str) -> None:
|
|
43
|
+
"""Set the active engine ID.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
engine_id: The engine ID to set as active
|
|
47
|
+
"""
|
|
48
|
+
cls._active_engine_id = engine_id
|
|
49
|
+
logger.debug("Set active engine ID to: %s", engine_id)
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def initialize_engine_id(cls) -> str:
|
|
53
|
+
"""Initialize the engine ID if not already set."""
|
|
54
|
+
if cls._active_engine_id is None:
|
|
55
|
+
engine_id = EngineIdentity.get_engine_id()
|
|
56
|
+
BaseEvent._engine_id = engine_id
|
|
57
|
+
cls._active_engine_id = engine_id
|
|
58
|
+
logger.debug("Initialized engine ID: %s", engine_id)
|
|
59
|
+
|
|
60
|
+
return cls._active_engine_id
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def get_engine_data(cls) -> dict:
|
|
64
|
+
"""Get the current engine data, creating default if it doesn't exist.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
dict: The current engine data
|
|
68
|
+
"""
|
|
69
|
+
return EngineIdentity.get_engine_data()
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def get_engine_name(cls) -> str:
|
|
73
|
+
"""Get the engine name.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
str: The engine name
|
|
77
|
+
"""
|
|
78
|
+
return EngineIdentity.get_engine_name()
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def set_engine_name(cls, engine_name: str) -> None:
|
|
82
|
+
"""Set and persist the current engine name.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
engine_name: The new engine name to set
|
|
86
|
+
"""
|
|
87
|
+
EngineIdentity.set_engine_name(engine_name)
|
|
88
|
+
logger.info("Updated engine name to: %s", engine_name)
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def get_all_engines(cls) -> list[dict]:
|
|
92
|
+
"""Get all registered engines.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
list[dict]: List of all engine data
|
|
96
|
+
"""
|
|
97
|
+
return EngineIdentity.get_all_engines()
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def get_default_engine_id(cls) -> str | None:
|
|
101
|
+
"""Get the default engine ID.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
str | None: The default engine ID or None if not set
|
|
105
|
+
"""
|
|
106
|
+
return EngineIdentity.get_default_engine_id()
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def set_default_engine_id(cls, engine_id: str) -> None:
|
|
110
|
+
"""Set the default engine ID.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
engine_id: The engine ID to set as default
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
ValueError: If engine_id is not found in registered engines
|
|
117
|
+
"""
|
|
118
|
+
try:
|
|
119
|
+
EngineIdentity.set_default_engine_id(engine_id)
|
|
120
|
+
logger.info("Set default engine ID to: %s", engine_id)
|
|
121
|
+
except ValueError as e:
|
|
122
|
+
logger.error("Failed to set default engine ID: %s", e)
|
|
123
|
+
raise
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def get_engine_data_file_path(cls) -> Path:
|
|
127
|
+
"""Get the path where engine data is stored (for debugging/inspection).
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Path: The path to the engine data file
|
|
131
|
+
"""
|
|
132
|
+
return EngineIdentity.get_engine_data_file_path()
|
|
133
|
+
|
|
134
|
+
@classmethod
|
|
135
|
+
def ensure_engine_initialized(cls) -> str:
|
|
136
|
+
"""Ensure engine is initialized and return the engine ID.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
str: The initialized engine ID
|
|
140
|
+
"""
|
|
141
|
+
cls.initialize_engine_id()
|
|
142
|
+
engine_id = cls.get_active_engine_id()
|
|
143
|
+
if engine_id is None:
|
|
144
|
+
msg = "Failed to initialize engine ID"
|
|
145
|
+
raise RuntimeError(msg)
|
|
146
|
+
return engine_id
|