griptape-nodes 0.52.1__py3-none-any.whl → 0.54.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 +8 -942
- griptape_nodes/__main__.py +6 -0
- griptape_nodes/app/app.py +48 -86
- griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +35 -5
- griptape_nodes/bootstrap/workflow_executors/workflow_executor.py +15 -1
- griptape_nodes/cli/__init__.py +1 -0
- griptape_nodes/cli/commands/__init__.py +1 -0
- griptape_nodes/cli/commands/config.py +74 -0
- griptape_nodes/cli/commands/engine.py +80 -0
- griptape_nodes/cli/commands/init.py +550 -0
- griptape_nodes/cli/commands/libraries.py +96 -0
- griptape_nodes/cli/commands/models.py +504 -0
- griptape_nodes/cli/commands/self.py +120 -0
- griptape_nodes/cli/main.py +56 -0
- griptape_nodes/cli/shared.py +75 -0
- griptape_nodes/common/__init__.py +1 -0
- griptape_nodes/common/directed_graph.py +71 -0
- griptape_nodes/drivers/storage/base_storage_driver.py +40 -20
- griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +24 -29
- griptape_nodes/drivers/storage/local_storage_driver.py +23 -14
- griptape_nodes/exe_types/core_types.py +60 -2
- griptape_nodes/exe_types/node_types.py +257 -38
- griptape_nodes/exe_types/param_components/__init__.py +1 -0
- griptape_nodes/exe_types/param_components/execution_status_component.py +138 -0
- griptape_nodes/machines/control_flow.py +195 -94
- griptape_nodes/machines/dag_builder.py +207 -0
- griptape_nodes/machines/fsm.py +10 -1
- griptape_nodes/machines/parallel_resolution.py +558 -0
- griptape_nodes/machines/{node_resolution.py → sequential_resolution.py} +30 -57
- griptape_nodes/node_library/library_registry.py +34 -1
- griptape_nodes/retained_mode/events/app_events.py +5 -1
- griptape_nodes/retained_mode/events/base_events.py +9 -9
- griptape_nodes/retained_mode/events/config_events.py +30 -0
- griptape_nodes/retained_mode/events/execution_events.py +2 -2
- griptape_nodes/retained_mode/events/model_events.py +296 -0
- griptape_nodes/retained_mode/events/node_events.py +4 -3
- griptape_nodes/retained_mode/griptape_nodes.py +34 -12
- griptape_nodes/retained_mode/managers/agent_manager.py +23 -5
- griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +3 -1
- griptape_nodes/retained_mode/managers/config_manager.py +44 -3
- griptape_nodes/retained_mode/managers/context_manager.py +6 -5
- griptape_nodes/retained_mode/managers/event_manager.py +8 -2
- griptape_nodes/retained_mode/managers/flow_manager.py +150 -206
- griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +1 -1
- griptape_nodes/retained_mode/managers/library_manager.py +35 -25
- griptape_nodes/retained_mode/managers/model_manager.py +1107 -0
- griptape_nodes/retained_mode/managers/node_manager.py +102 -220
- griptape_nodes/retained_mode/managers/object_manager.py +11 -5
- griptape_nodes/retained_mode/managers/os_manager.py +28 -13
- griptape_nodes/retained_mode/managers/secrets_manager.py +8 -4
- griptape_nodes/retained_mode/managers/settings.py +116 -7
- griptape_nodes/retained_mode/managers/static_files_manager.py +85 -12
- griptape_nodes/retained_mode/managers/sync_manager.py +17 -9
- griptape_nodes/retained_mode/managers/workflow_manager.py +186 -192
- griptape_nodes/retained_mode/retained_mode.py +19 -0
- griptape_nodes/servers/__init__.py +1 -0
- griptape_nodes/{mcp_server/server.py → servers/mcp.py} +1 -1
- griptape_nodes/{app/api.py → servers/static.py} +43 -40
- griptape_nodes/traits/add_param_button.py +1 -1
- griptape_nodes/traits/button.py +334 -6
- griptape_nodes/traits/color_picker.py +66 -0
- griptape_nodes/traits/multi_options.py +188 -0
- griptape_nodes/traits/numbers_selector.py +77 -0
- griptape_nodes/traits/options.py +93 -2
- griptape_nodes/traits/traits.json +4 -0
- griptape_nodes/utils/async_utils.py +31 -0
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.54.0.dist-info}/METADATA +4 -1
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.54.0.dist-info}/RECORD +71 -48
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.54.0.dist-info}/WHEEL +1 -1
- /griptape_nodes/{mcp_server → servers}/ws_request_manager.py +0 -0
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.54.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
from enum import StrEnum
|
|
4
5
|
from queue import Queue
|
|
5
|
-
from typing import TYPE_CHECKING, cast
|
|
6
|
+
from typing import TYPE_CHECKING, NamedTuple, cast
|
|
6
7
|
|
|
7
8
|
from griptape_nodes.exe_types.connections import Connections
|
|
8
9
|
from griptape_nodes.exe_types.core_types import (
|
|
@@ -15,11 +16,15 @@ from griptape_nodes.exe_types.core_types import (
|
|
|
15
16
|
from griptape_nodes.exe_types.flow import ControlFlow
|
|
16
17
|
from griptape_nodes.exe_types.node_types import BaseNode, ErrorProxyNode, NodeResolutionState, StartLoopNode, StartNode
|
|
17
18
|
from griptape_nodes.machines.control_flow import CompleteState, ControlFlowMachine
|
|
19
|
+
from griptape_nodes.machines.dag_builder import DagBuilder
|
|
20
|
+
from griptape_nodes.machines.parallel_resolution import ParallelResolutionMachine
|
|
21
|
+
from griptape_nodes.machines.sequential_resolution import SequentialResolutionMachine
|
|
18
22
|
from griptape_nodes.retained_mode.events.base_events import (
|
|
19
23
|
ExecutionEvent,
|
|
20
24
|
ExecutionGriptapeNodeEvent,
|
|
21
25
|
FlushParameterChangesRequest,
|
|
22
26
|
FlushParameterChangesResultSuccess,
|
|
27
|
+
ResultDetails,
|
|
23
28
|
)
|
|
24
29
|
from griptape_nodes.retained_mode.events.connection_events import (
|
|
25
30
|
CreateConnectionRequest,
|
|
@@ -120,15 +125,29 @@ if TYPE_CHECKING:
|
|
|
120
125
|
logger = logging.getLogger("griptape_nodes")
|
|
121
126
|
|
|
122
127
|
|
|
128
|
+
class DagExecutionType(StrEnum):
|
|
129
|
+
START_NODE = "start_node"
|
|
130
|
+
CONTROL_NODE = "control_node"
|
|
131
|
+
DATA_NODE = "data_node"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class QueueItem(NamedTuple):
|
|
135
|
+
"""Represents an item in the flow execution queue."""
|
|
136
|
+
|
|
137
|
+
node: BaseNode
|
|
138
|
+
dag_execution_type: DagExecutionType
|
|
139
|
+
|
|
140
|
+
|
|
123
141
|
class FlowManager:
|
|
124
142
|
_name_to_parent_name: dict[str, str | None]
|
|
125
143
|
_flow_to_referenced_workflow_name: dict[ControlFlow, str]
|
|
126
144
|
_connections: Connections
|
|
127
145
|
|
|
128
146
|
# Global execution state (moved from individual ControlFlows)
|
|
129
|
-
_global_flow_queue: Queue[
|
|
147
|
+
_global_flow_queue: Queue[QueueItem]
|
|
130
148
|
_global_control_flow_machine: ControlFlowMachine | None
|
|
131
149
|
_global_single_node_resolution: bool
|
|
150
|
+
_global_dag_builder: DagBuilder
|
|
132
151
|
|
|
133
152
|
def __init__(self, event_manager: EventManager) -> None:
|
|
134
153
|
event_manager.assign_manager_to_request_type(CreateFlowRequest, self.on_create_flow_request)
|
|
@@ -169,9 +188,22 @@ class FlowManager:
|
|
|
169
188
|
self._connections = Connections()
|
|
170
189
|
|
|
171
190
|
# Initialize global execution state
|
|
172
|
-
self._global_flow_queue = Queue[
|
|
173
|
-
self._global_control_flow_machine = None #
|
|
191
|
+
self._global_flow_queue = Queue[QueueItem]()
|
|
192
|
+
self._global_control_flow_machine = None # Track the current control flow machine
|
|
174
193
|
self._global_single_node_resolution = False
|
|
194
|
+
self._global_dag_builder = DagBuilder()
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def global_single_node_resolution(self) -> bool:
|
|
198
|
+
return self._global_single_node_resolution
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def global_flow_queue(self) -> Queue[QueueItem]:
|
|
202
|
+
return self._global_flow_queue
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def global_dag_builder(self) -> DagBuilder:
|
|
206
|
+
return self._global_dag_builder
|
|
175
207
|
|
|
176
208
|
def get_connections(self) -> Connections:
|
|
177
209
|
"""Get the connections instance."""
|
|
@@ -238,10 +270,12 @@ class FlowManager:
|
|
|
238
270
|
def on_get_top_level_flow_request(self, request: GetTopLevelFlowRequest) -> ResultPayload: # noqa: ARG002 (the request has to be assigned to the method)
|
|
239
271
|
for flow_name, parent in self._name_to_parent_name.items():
|
|
240
272
|
if parent is None:
|
|
241
|
-
return GetTopLevelFlowResultSuccess(
|
|
273
|
+
return GetTopLevelFlowResultSuccess(
|
|
274
|
+
flow_name=flow_name, result_details=f"Successfully found top level flow: '{flow_name}'"
|
|
275
|
+
)
|
|
242
276
|
msg = "Attempted to get top level flow, but no such flow exists"
|
|
243
277
|
logger.debug(msg)
|
|
244
|
-
return GetTopLevelFlowResultSuccess(flow_name=None)
|
|
278
|
+
return GetTopLevelFlowResultSuccess(flow_name=None, result_details=msg)
|
|
245
279
|
|
|
246
280
|
def on_get_flow_details_request(self, request: GetFlowDetailsRequest) -> ResultPayload:
|
|
247
281
|
flow_name = request.flow_name
|
|
@@ -251,7 +285,6 @@ class FlowManager:
|
|
|
251
285
|
# We want to get details for whatever is at the top of the Current Context.
|
|
252
286
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
253
287
|
details = "Attempted to get Flow details from the Current Context. Failed because the Current Context was empty."
|
|
254
|
-
logger.error(details)
|
|
255
288
|
return GetFlowDetailsResultFailure(result_details=details)
|
|
256
289
|
flow = GriptapeNodes.ContextManager().get_current_flow()
|
|
257
290
|
flow_name = flow.name
|
|
@@ -261,14 +294,12 @@ class FlowManager:
|
|
|
261
294
|
details = (
|
|
262
295
|
f"Attempted to get Flow details for '{flow_name}'. Failed because no Flow with that name exists."
|
|
263
296
|
)
|
|
264
|
-
logger.error(details)
|
|
265
297
|
return GetFlowDetailsResultFailure(result_details=details)
|
|
266
298
|
|
|
267
299
|
try:
|
|
268
300
|
parent_flow_name = self.get_parent_flow(flow_name)
|
|
269
301
|
except ValueError:
|
|
270
302
|
details = f"Attempted to get Flow details for '{flow_name}'. Failed because Flow does not exist in parent mapping."
|
|
271
|
-
logger.error(details)
|
|
272
303
|
return GetFlowDetailsResultFailure(result_details=details)
|
|
273
304
|
|
|
274
305
|
referenced_workflow_name = None
|
|
@@ -276,10 +307,8 @@ class FlowManager:
|
|
|
276
307
|
referenced_workflow_name = self.get_referenced_workflow_name(flow)
|
|
277
308
|
|
|
278
309
|
details = f"Successfully retrieved Flow details for '{flow_name}'."
|
|
279
|
-
logger.debug(details)
|
|
280
310
|
return GetFlowDetailsResultSuccess(
|
|
281
|
-
referenced_workflow_name=referenced_workflow_name,
|
|
282
|
-
parent_flow_name=parent_flow_name,
|
|
311
|
+
referenced_workflow_name=referenced_workflow_name, parent_flow_name=parent_flow_name, result_details=details
|
|
283
312
|
)
|
|
284
313
|
|
|
285
314
|
def on_get_flow_metadata_request(self, request: GetFlowMetadataRequest) -> ResultPayload:
|
|
@@ -289,7 +318,6 @@ class FlowManager:
|
|
|
289
318
|
# Get from the current context.
|
|
290
319
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
291
320
|
details = "Attempted to get metadata for a Flow from the Current Context. Failed because the Current Context is empty."
|
|
292
|
-
logger.error(details)
|
|
293
321
|
return GetFlowMetadataResultFailure(result_details=details)
|
|
294
322
|
|
|
295
323
|
flow = GriptapeNodes.ContextManager().get_current_flow()
|
|
@@ -301,14 +329,12 @@ class FlowManager:
|
|
|
301
329
|
flow = obj_mgr.attempt_get_object_by_name_as_type(flow_name, ControlFlow)
|
|
302
330
|
if flow is None:
|
|
303
331
|
details = f"Attempted to get metadata for a Flow '{flow_name}', but no such Flow was found."
|
|
304
|
-
logger.error(details)
|
|
305
332
|
return GetFlowMetadataResultFailure(result_details=details)
|
|
306
333
|
|
|
307
334
|
metadata = flow.metadata
|
|
308
335
|
details = f"Successfully retrieved metadata for a Flow '{flow_name}'."
|
|
309
|
-
logger.debug(details)
|
|
310
336
|
|
|
311
|
-
return GetFlowMetadataResultSuccess(metadata=metadata)
|
|
337
|
+
return GetFlowMetadataResultSuccess(metadata=metadata, result_details=details)
|
|
312
338
|
|
|
313
339
|
def on_set_flow_metadata_request(self, request: SetFlowMetadataRequest) -> ResultPayload:
|
|
314
340
|
flow_name = request.flow_name
|
|
@@ -317,7 +343,6 @@ class FlowManager:
|
|
|
317
343
|
# Get from the current context.
|
|
318
344
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
319
345
|
details = "Attempted to set metadata for a Flow from the Current Context. Failed because the Current Context is empty."
|
|
320
|
-
logger.error(details)
|
|
321
346
|
return SetFlowMetadataResultFailure(result_details=details)
|
|
322
347
|
|
|
323
348
|
flow = GriptapeNodes.ContextManager().get_current_flow()
|
|
@@ -329,16 +354,14 @@ class FlowManager:
|
|
|
329
354
|
flow = obj_mgr.attempt_get_object_by_name_as_type(flow_name, ControlFlow)
|
|
330
355
|
if flow is None:
|
|
331
356
|
details = f"Attempted to set metadata for a Flow '{flow_name}', but no such Flow was found."
|
|
332
|
-
logger.error(details)
|
|
333
357
|
return SetFlowMetadataResultFailure(result_details=details)
|
|
334
358
|
|
|
335
359
|
# We can't completely overwrite metadata.
|
|
336
360
|
for key, value in request.metadata.items():
|
|
337
361
|
flow.metadata[key] = value
|
|
338
362
|
details = f"Successfully set metadata for a Flow '{flow_name}'."
|
|
339
|
-
logger.debug(details)
|
|
340
363
|
|
|
341
|
-
return SetFlowMetadataResultSuccess()
|
|
364
|
+
return SetFlowMetadataResultSuccess(result_details=details)
|
|
342
365
|
|
|
343
366
|
def does_canvas_exist(self) -> bool:
|
|
344
367
|
"""Determines if there is already an existing flow with no parent flow.Returns True if there is an existing flow with no parent flow.Return False if there is no existing flow with no parent flow."""
|
|
@@ -368,13 +391,11 @@ class FlowManager:
|
|
|
368
391
|
if self.does_canvas_exist():
|
|
369
392
|
# We're trying to create the canvas. Ensure that parent does NOT already exist.
|
|
370
393
|
details = "Attempted to create a Flow as the Canvas (top-level Flow with no parents), but the Canvas already exists."
|
|
371
|
-
logger.error(details)
|
|
372
394
|
result = CreateFlowResultFailure(result_details=details)
|
|
373
395
|
return result
|
|
374
396
|
# Now our parent exists, right?
|
|
375
397
|
elif parent is None:
|
|
376
398
|
details = f"Attempted to create a Flow with a parent '{request.parent_flow_name}', but no parent with that name could be found."
|
|
377
|
-
logger.error(details)
|
|
378
399
|
|
|
379
400
|
result = CreateFlowResultFailure(result_details=details)
|
|
380
401
|
|
|
@@ -383,7 +404,6 @@ class FlowManager:
|
|
|
383
404
|
# We need to have a current workflow context to proceed.
|
|
384
405
|
if not GriptapeNodes.ContextManager().has_current_workflow():
|
|
385
406
|
details = "Attempted to create a Flow, but no Workflow was active in the Current Context."
|
|
386
|
-
logger.error(details)
|
|
387
407
|
return CreateFlowResultFailure(result_details=details)
|
|
388
408
|
|
|
389
409
|
# Create it.
|
|
@@ -414,8 +434,9 @@ class FlowManager:
|
|
|
414
434
|
details = f"{details} WARNING: Had to rename from original Flow requested '{request.flow_name}' as an object with this name already existed."
|
|
415
435
|
log_level = logging.WARNING
|
|
416
436
|
|
|
417
|
-
|
|
418
|
-
|
|
437
|
+
result = CreateFlowResultSuccess(
|
|
438
|
+
flow_name=final_flow_name, result_details=ResultDetails(message=details, level=log_level)
|
|
439
|
+
)
|
|
419
440
|
return result
|
|
420
441
|
|
|
421
442
|
# This needs to have a lot of branches to check the flow in all possible situations. In Current Context, or when the name is passed in.
|
|
@@ -428,7 +449,6 @@ class FlowManager:
|
|
|
428
449
|
details = (
|
|
429
450
|
"Attempted to delete a Flow from the Current Context. Failed because the Current Context was empty."
|
|
430
451
|
)
|
|
431
|
-
logger.error(details)
|
|
432
452
|
result = DeleteFlowResultFailure(result_details=details)
|
|
433
453
|
return result
|
|
434
454
|
# We pop it off here, but we'll re-add it using context in a moment.
|
|
@@ -440,14 +460,12 @@ class FlowManager:
|
|
|
440
460
|
flow = obj_mgr.attempt_get_object_by_name_as_type(flow_name, ControlFlow)
|
|
441
461
|
if flow is None:
|
|
442
462
|
details = f"Attempted to delete Flow '{flow_name}', but no Flow with that name could be found."
|
|
443
|
-
logger.error(details)
|
|
444
463
|
result = DeleteFlowResultFailure(result_details=details)
|
|
445
464
|
return result
|
|
446
465
|
if self.check_for_existing_running_flow():
|
|
447
466
|
result = GriptapeNodes.handle_request(CancelFlowRequest(flow_name=flow.name))
|
|
448
467
|
if not result.succeeded():
|
|
449
468
|
details = f"Attempted to delete flow '{flow_name}'. Failed because running flow could not cancel."
|
|
450
|
-
logger.error(details)
|
|
451
469
|
return DeleteFlowResultFailure(result_details=details)
|
|
452
470
|
|
|
453
471
|
# Let this Flow assume the Current Context while we delete everything within it.
|
|
@@ -457,7 +475,6 @@ class FlowManager:
|
|
|
457
475
|
list_nodes_result = GriptapeNodes.handle_request(list_nodes_request)
|
|
458
476
|
if not isinstance(list_nodes_result, ListNodesInFlowResultSuccess):
|
|
459
477
|
details = f"Attempted to delete Flow '{flow.name}', but failed while attempting to get the list of Nodes owned by this Flow."
|
|
460
|
-
logger.error(details)
|
|
461
478
|
result = DeleteFlowResultFailure(result_details=details)
|
|
462
479
|
return result
|
|
463
480
|
node_names = list_nodes_result.node_names
|
|
@@ -466,7 +483,6 @@ class FlowManager:
|
|
|
466
483
|
delete_node_result = GriptapeNodes.handle_request(delete_node_request)
|
|
467
484
|
if isinstance(delete_node_result, DeleteNodeResultFailure):
|
|
468
485
|
details = f"Attempted to delete Flow '{flow.name}', but failed while attempting to delete child Node '{node_name}'."
|
|
469
|
-
logger.error(details)
|
|
470
486
|
result = DeleteFlowResultFailure(result_details=details)
|
|
471
487
|
return result
|
|
472
488
|
|
|
@@ -478,7 +494,6 @@ class FlowManager:
|
|
|
478
494
|
list_flows_result = GriptapeNodes.handle_request(list_flows_request)
|
|
479
495
|
if not isinstance(list_flows_result, ListFlowsInCurrentContextResultSuccess):
|
|
480
496
|
details = f"Attempted to delete Flow '{flow_name}', but failed while attempting to get the list of Flows owned by this Flow."
|
|
481
|
-
logger.error(details)
|
|
482
497
|
result = DeleteFlowResultFailure(result_details=details)
|
|
483
498
|
return result
|
|
484
499
|
flow_names = list_flows_result.flow_names
|
|
@@ -489,7 +504,6 @@ class FlowManager:
|
|
|
489
504
|
details = (
|
|
490
505
|
f"Attempted to delete Flow '{child_flow_name}', but no Flow with that name could be found."
|
|
491
506
|
)
|
|
492
|
-
logger.error(details)
|
|
493
507
|
result = DeleteFlowResultFailure(result_details=details)
|
|
494
508
|
return result
|
|
495
509
|
with GriptapeNodes.ContextManager().flow(flow=child_flow):
|
|
@@ -498,7 +512,6 @@ class FlowManager:
|
|
|
498
512
|
delete_flow_result = GriptapeNodes.handle_request(delete_flow_request)
|
|
499
513
|
if isinstance(delete_flow_result, DeleteFlowResultFailure):
|
|
500
514
|
details = f"Attempted to delete Flow '{flow.name}', but failed while attempting to delete child Flow '{child_flow.name}'."
|
|
501
|
-
logger.error(details)
|
|
502
515
|
result = DeleteFlowResultFailure(result_details=details)
|
|
503
516
|
return result
|
|
504
517
|
|
|
@@ -511,31 +524,33 @@ class FlowManager:
|
|
|
511
524
|
if flow in self._flow_to_referenced_workflow_name:
|
|
512
525
|
del self._flow_to_referenced_workflow_name[flow]
|
|
513
526
|
|
|
527
|
+
# Clean up ControlFlowMachine and DAG orchestrator for this flow
|
|
528
|
+
self._global_control_flow_machine = None
|
|
529
|
+
self._global_dag_builder.clear()
|
|
530
|
+
|
|
514
531
|
details = f"Successfully deleted Flow '{flow_name}'."
|
|
515
|
-
|
|
516
|
-
result = DeleteFlowResultSuccess()
|
|
532
|
+
result = DeleteFlowResultSuccess(result_details=details)
|
|
517
533
|
return result
|
|
518
534
|
|
|
519
535
|
def on_get_is_flow_running_request(self, request: GetIsFlowRunningRequest) -> ResultPayload:
|
|
520
536
|
obj_mgr = GriptapeNodes.ObjectManager()
|
|
521
537
|
if request.flow_name is None:
|
|
522
538
|
details = "Attempted to get Flow, but no flow name was provided."
|
|
523
|
-
logger.error(details)
|
|
524
539
|
return GetIsFlowRunningResultFailure(result_details=details)
|
|
525
540
|
flow = obj_mgr.attempt_get_object_by_name_as_type(request.flow_name, ControlFlow)
|
|
526
541
|
if flow is None:
|
|
527
542
|
details = f"Attempted to get Flow '{request.flow_name}', but no Flow with that name could be found."
|
|
528
|
-
logger.error(details)
|
|
529
543
|
result = GetIsFlowRunningResultFailure(result_details=details)
|
|
530
544
|
return result
|
|
531
545
|
try:
|
|
532
546
|
is_running = self.check_for_existing_running_flow()
|
|
533
547
|
except Exception:
|
|
534
548
|
details = f"Error while trying to get status of '{request.flow_name}'."
|
|
535
|
-
logger.error(details)
|
|
536
549
|
result = GetIsFlowRunningResultFailure(result_details=details)
|
|
537
550
|
return result
|
|
538
|
-
return GetIsFlowRunningResultSuccess(
|
|
551
|
+
return GetIsFlowRunningResultSuccess(
|
|
552
|
+
is_running=is_running, result_details=f"Successfully checked if flow is running: {is_running}"
|
|
553
|
+
)
|
|
539
554
|
|
|
540
555
|
def on_list_nodes_in_flow_request(self, request: ListNodesInFlowRequest) -> ResultPayload:
|
|
541
556
|
flow_name = request.flow_name
|
|
@@ -544,7 +559,6 @@ class FlowManager:
|
|
|
544
559
|
# First check if we have a current flow
|
|
545
560
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
546
561
|
details = "Attempted to list Nodes in a Flow in the Current Context. Failed because the Current Context was empty."
|
|
547
|
-
logger.error(details)
|
|
548
562
|
result = ListNodesInFlowResultFailure(result_details=details)
|
|
549
563
|
return result
|
|
550
564
|
# Get the current flow from context
|
|
@@ -558,15 +572,13 @@ class FlowManager:
|
|
|
558
572
|
details = (
|
|
559
573
|
f"Attempted to list Nodes in Flow '{flow_name}'. Failed because no Flow with that name could be found."
|
|
560
574
|
)
|
|
561
|
-
logger.error(details)
|
|
562
575
|
result = ListNodesInFlowResultFailure(result_details=details)
|
|
563
576
|
return result
|
|
564
577
|
|
|
565
578
|
ret_list = list(flow.nodes.keys())
|
|
566
579
|
details = f"Successfully got the list of Nodes within Flow '{flow_name}'."
|
|
567
|
-
logger.debug(details)
|
|
568
580
|
|
|
569
|
-
result = ListNodesInFlowResultSuccess(node_names=ret_list)
|
|
581
|
+
result = ListNodesInFlowResultSuccess(node_names=ret_list, result_details=details)
|
|
570
582
|
return result
|
|
571
583
|
|
|
572
584
|
def on_list_flows_in_flow_request(self, request: ListFlowsInFlowRequest) -> ResultPayload:
|
|
@@ -576,7 +588,6 @@ class FlowManager:
|
|
|
576
588
|
flow = obj_mgr.attempt_get_object_by_name_as_type(request.parent_flow_name, ControlFlow)
|
|
577
589
|
if flow is None:
|
|
578
590
|
details = f"Attempted to list Flows that are children of Flow '{request.parent_flow_name}', but no Flow with that name could be found."
|
|
579
|
-
logger.error(details)
|
|
580
591
|
result = ListFlowsInFlowResultFailure(result_details=details)
|
|
581
592
|
return result
|
|
582
593
|
|
|
@@ -587,9 +598,8 @@ class FlowManager:
|
|
|
587
598
|
ret_list.append(flow_name)
|
|
588
599
|
|
|
589
600
|
details = f"Successfully got the list of Flows that are direct children of Flow '{request.parent_flow_name}'."
|
|
590
|
-
logger.debug(details)
|
|
591
601
|
|
|
592
|
-
result = ListFlowsInFlowResultSuccess(flow_names=ret_list)
|
|
602
|
+
result = ListFlowsInFlowResultSuccess(flow_names=ret_list, result_details=details)
|
|
593
603
|
return result
|
|
594
604
|
|
|
595
605
|
def get_flow_by_name(self, flow_name: str) -> ControlFlow:
|
|
@@ -623,7 +633,6 @@ class FlowManager:
|
|
|
623
633
|
# First check if we have a current node
|
|
624
634
|
if not GriptapeNodes.ContextManager().has_current_node():
|
|
625
635
|
details = "Attempted to create a Connection with a source node from the Current Context. Failed because the Current Context was empty."
|
|
626
|
-
logger.error(details)
|
|
627
636
|
return CreateConnectionResultFailure(result_details=details)
|
|
628
637
|
|
|
629
638
|
# Get the current node from context
|
|
@@ -634,7 +643,6 @@ class FlowManager:
|
|
|
634
643
|
source_node = GriptapeNodes.NodeManager().get_node_by_name(source_node_name)
|
|
635
644
|
except ValueError as err:
|
|
636
645
|
details = f'Connection failed: "{source_node_name}" does not exist. Error: {err}.'
|
|
637
|
-
logger.error(details)
|
|
638
646
|
|
|
639
647
|
return CreateConnectionResultFailure(result_details=details)
|
|
640
648
|
|
|
@@ -644,7 +652,6 @@ class FlowManager:
|
|
|
644
652
|
# First check if we have a current node
|
|
645
653
|
if not GriptapeNodes.ContextManager().has_current_node():
|
|
646
654
|
details = "Attempted to create a Connection with the target node from the Current Context. Failed because the Current Context was empty."
|
|
647
|
-
logger.error(details)
|
|
648
655
|
return CreateConnectionResultFailure(result_details=details)
|
|
649
656
|
|
|
650
657
|
# Get the current node from context
|
|
@@ -655,7 +662,6 @@ class FlowManager:
|
|
|
655
662
|
target_node = GriptapeNodes.NodeManager().get_node_by_name(target_node_name)
|
|
656
663
|
except ValueError as err:
|
|
657
664
|
details = f'Connection failed: "{target_node_name}" does not exist. Error: {err}.'
|
|
658
|
-
logger.error(details)
|
|
659
665
|
return CreateConnectionResultFailure(result_details=details)
|
|
660
666
|
|
|
661
667
|
# The two nodes exist.
|
|
@@ -666,7 +672,6 @@ class FlowManager:
|
|
|
666
672
|
self.get_flow_by_name(flow_name=source_flow_name)
|
|
667
673
|
except KeyError as err:
|
|
668
674
|
details = f'Connection "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}" failed: {err}.'
|
|
669
|
-
logger.error(details)
|
|
670
675
|
return CreateConnectionResultFailure(result_details=details)
|
|
671
676
|
|
|
672
677
|
target_flow_name = None
|
|
@@ -675,7 +680,6 @@ class FlowManager:
|
|
|
675
680
|
self.get_flow_by_name(flow_name=target_flow_name)
|
|
676
681
|
except KeyError as err:
|
|
677
682
|
details = f'Connection "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}" failed: {err}.'
|
|
678
|
-
logger.error(details)
|
|
679
683
|
return CreateConnectionResultFailure(result_details=details)
|
|
680
684
|
|
|
681
685
|
# Cross-flow connections are now supported via global connection storage
|
|
@@ -696,14 +700,12 @@ class FlowManager:
|
|
|
696
700
|
source_param = source_node.get_parameter_by_name(request.source_parameter_name)
|
|
697
701
|
if source_param is None:
|
|
698
702
|
details = f'Connection failed: "{source_node_name}.{request.source_parameter_name}" not found'
|
|
699
|
-
logger.error(details)
|
|
700
703
|
return CreateConnectionResultFailure(result_details=details)
|
|
701
704
|
|
|
702
705
|
target_param = target_node.get_parameter_by_name(request.target_parameter_name)
|
|
703
706
|
if target_param is None:
|
|
704
707
|
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/860
|
|
705
708
|
details = f'Connection failed: "{target_node_name}.{request.target_parameter_name}" not found'
|
|
706
|
-
logger.error(details)
|
|
707
709
|
return CreateConnectionResultFailure(result_details=details)
|
|
708
710
|
# Validate parameter modes accept this type of connection.
|
|
709
711
|
source_modes_allowed = source_param.allowed_modes
|
|
@@ -711,19 +713,16 @@ class FlowManager:
|
|
|
711
713
|
details = (
|
|
712
714
|
f'Connection failed: "{source_node_name}.{request.source_parameter_name}" is not an allowed OUTPUT'
|
|
713
715
|
)
|
|
714
|
-
logger.error(details)
|
|
715
716
|
return CreateConnectionResultFailure(result_details=details)
|
|
716
717
|
|
|
717
718
|
target_modes_allowed = target_param.allowed_modes
|
|
718
719
|
if ParameterMode.INPUT not in target_modes_allowed:
|
|
719
720
|
details = f'Connection failed: "{target_node_name}.{request.target_parameter_name}" is not an allowed INPUT'
|
|
720
|
-
logger.error(details)
|
|
721
721
|
return CreateConnectionResultFailure(result_details=details)
|
|
722
722
|
|
|
723
723
|
# Validate that the data type from the source is allowed by the target.
|
|
724
724
|
if not target_param.is_incoming_type_allowed(source_param.output_type):
|
|
725
725
|
details = f'Connection failed on type mismatch "{source_node_name}.{request.source_parameter_name}" type({source_param.output_type}) to "{target_node_name}.{request.target_parameter_name}" types({target_param.input_types}) '
|
|
726
|
-
logger.error(details)
|
|
727
726
|
return CreateConnectionResultFailure(result_details=details)
|
|
728
727
|
|
|
729
728
|
# Ask each node involved to bless this union.
|
|
@@ -735,7 +734,6 @@ class FlowManager:
|
|
|
735
734
|
details = (
|
|
736
735
|
f'Connection failed : "{source_node_name}.{request.source_parameter_name}" rejected the connection '
|
|
737
736
|
)
|
|
738
|
-
logger.error(details)
|
|
739
737
|
return CreateConnectionResultFailure(result_details=details)
|
|
740
738
|
|
|
741
739
|
if not target_node.allow_incoming_connection(
|
|
@@ -746,7 +744,6 @@ class FlowManager:
|
|
|
746
744
|
details = (
|
|
747
745
|
f'Connection failed : "{target_node_name}.{request.target_parameter_name}" rejected the connection '
|
|
748
746
|
)
|
|
749
|
-
logger.error(details)
|
|
750
747
|
return CreateConnectionResultFailure(result_details=details)
|
|
751
748
|
|
|
752
749
|
# Based on user feedback, if a connection already exists in a scenario where only ONE such connection can exist
|
|
@@ -786,11 +783,9 @@ class FlowManager:
|
|
|
786
783
|
delete_old_result = GriptapeNodes.handle_request(delete_old_request)
|
|
787
784
|
if delete_old_result.failed():
|
|
788
785
|
details = f"Attempted to connect '{source_node_name}.{request.source_parameter_name}'. Failed because there was a previous connection from '{old_source_node_name}.{old_source_param_name}' to '{old_target_node_name}.{old_target_param_name}' that could not be deleted."
|
|
789
|
-
logger.error(details)
|
|
790
786
|
return CreateConnectionResultFailure(result_details=details)
|
|
791
787
|
|
|
792
788
|
details = f"Deleted the previous connection from '{old_source_node_name}.{old_source_param_name}' to '{old_target_node_name}.{old_target_param_name}' to make room for the new connection."
|
|
793
|
-
logger.debug(details)
|
|
794
789
|
try:
|
|
795
790
|
# Actually create the Connection.
|
|
796
791
|
self._connections.add_connection(
|
|
@@ -801,7 +796,6 @@ class FlowManager:
|
|
|
801
796
|
)
|
|
802
797
|
except ValueError as e:
|
|
803
798
|
details = f'Connection failed: "{e}"'
|
|
804
|
-
logger.error(details)
|
|
805
799
|
|
|
806
800
|
# Attempt to restore any old connection that may have been present.
|
|
807
801
|
if (
|
|
@@ -820,7 +814,6 @@ class FlowManager:
|
|
|
820
814
|
create_old_connection_result = GriptapeNodes.handle_request(create_old_connection_request)
|
|
821
815
|
if create_old_connection_result.failed():
|
|
822
816
|
details = "Failed attempting to restore the old Connection after failing the replacement. A thousand pardons."
|
|
823
|
-
logger.error(details)
|
|
824
817
|
return CreateConnectionResultFailure(result_details=details)
|
|
825
818
|
|
|
826
819
|
# Let the source make any internal handling decisions now that the Connection has been made.
|
|
@@ -836,7 +829,6 @@ class FlowManager:
|
|
|
836
829
|
)
|
|
837
830
|
|
|
838
831
|
details = f'Connected "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}"'
|
|
839
|
-
logger.debug(details)
|
|
840
832
|
|
|
841
833
|
# Now update the parameter values if it exists.
|
|
842
834
|
# check if it's been resolved/has a value in parameter_output_values
|
|
@@ -879,7 +871,7 @@ class FlowManager:
|
|
|
879
871
|
if isinstance(target_node, ErrorProxyNode):
|
|
880
872
|
target_node.set_post_init_connections_modified()
|
|
881
873
|
|
|
882
|
-
result = CreateConnectionResultSuccess()
|
|
874
|
+
result = CreateConnectionResultSuccess(result_details=details)
|
|
883
875
|
|
|
884
876
|
return result
|
|
885
877
|
|
|
@@ -893,7 +885,6 @@ class FlowManager:
|
|
|
893
885
|
# First check if we have a current node
|
|
894
886
|
if not GriptapeNodes.ContextManager().has_current_node():
|
|
895
887
|
details = "Attempted to delete a Connection with a source node from the Current Context. Failed because the Current Context was empty."
|
|
896
|
-
logger.error(details)
|
|
897
888
|
return DeleteConnectionResultFailure(result_details=details)
|
|
898
889
|
|
|
899
890
|
# Get the current node from context
|
|
@@ -904,7 +895,6 @@ class FlowManager:
|
|
|
904
895
|
source_node = GriptapeNodes.NodeManager().get_node_by_name(source_node_name)
|
|
905
896
|
except ValueError as err:
|
|
906
897
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
|
|
907
|
-
logger.error(details)
|
|
908
898
|
|
|
909
899
|
return DeleteConnectionResultFailure(result_details=details)
|
|
910
900
|
|
|
@@ -913,7 +903,6 @@ class FlowManager:
|
|
|
913
903
|
# First check if we have a current node
|
|
914
904
|
if not GriptapeNodes.ContextManager().has_current_node():
|
|
915
905
|
details = "Attempted to delete a Connection with a target node from the Current Context. Failed because the Current Context was empty."
|
|
916
|
-
logger.error(details)
|
|
917
906
|
return DeleteConnectionResultFailure(result_details=details)
|
|
918
907
|
|
|
919
908
|
# Get the current node from context
|
|
@@ -924,7 +913,6 @@ class FlowManager:
|
|
|
924
913
|
target_node = GriptapeNodes.NodeManager().get_node_by_name(target_node_name)
|
|
925
914
|
except ValueError as err:
|
|
926
915
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
|
|
927
|
-
logger.error(details)
|
|
928
916
|
|
|
929
917
|
return DeleteConnectionResultFailure(result_details=details)
|
|
930
918
|
|
|
@@ -936,7 +924,6 @@ class FlowManager:
|
|
|
936
924
|
self.get_flow_by_name(flow_name=source_flow_name)
|
|
937
925
|
except KeyError as err:
|
|
938
926
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
|
|
939
|
-
logger.error(details)
|
|
940
927
|
|
|
941
928
|
return DeleteConnectionResultFailure(result_details=details)
|
|
942
929
|
|
|
@@ -946,7 +933,6 @@ class FlowManager:
|
|
|
946
933
|
self.get_flow_by_name(flow_name=target_flow_name)
|
|
947
934
|
except KeyError as err:
|
|
948
935
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
|
|
949
|
-
logger.error(details)
|
|
950
936
|
|
|
951
937
|
return DeleteConnectionResultFailure(result_details=details)
|
|
952
938
|
|
|
@@ -956,14 +942,12 @@ class FlowManager:
|
|
|
956
942
|
source_param = source_node.get_parameter_by_name(request.source_parameter_name)
|
|
957
943
|
if source_param is None:
|
|
958
944
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" Not found.'
|
|
959
|
-
logger.error(details)
|
|
960
945
|
|
|
961
946
|
return DeleteConnectionResultFailure(result_details=details)
|
|
962
947
|
|
|
963
948
|
target_param = target_node.get_parameter_by_name(request.target_parameter_name)
|
|
964
949
|
if target_param is None:
|
|
965
950
|
details = f'Connection not deleted "{target_node_name}.{request.target_parameter_name}" Not found.'
|
|
966
|
-
logger.error(details)
|
|
967
951
|
|
|
968
952
|
return DeleteConnectionResultFailure(result_details=details)
|
|
969
953
|
|
|
@@ -975,7 +959,6 @@ class FlowManager:
|
|
|
975
959
|
target_parameter=target_param,
|
|
976
960
|
):
|
|
977
961
|
details = f'Connection does not exist: "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}"'
|
|
978
|
-
logger.error(details)
|
|
979
962
|
|
|
980
963
|
return DeleteConnectionResultFailure(result_details=details)
|
|
981
964
|
|
|
@@ -987,7 +970,6 @@ class FlowManager:
|
|
|
987
970
|
target_parameter=target_param.name,
|
|
988
971
|
):
|
|
989
972
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Unknown failure.'
|
|
990
|
-
logger.error(details)
|
|
991
973
|
|
|
992
974
|
return DeleteConnectionResultFailure(result_details=details)
|
|
993
975
|
|
|
@@ -1020,7 +1002,6 @@ class FlowManager:
|
|
|
1020
1002
|
)
|
|
1021
1003
|
|
|
1022
1004
|
details = f'Connection "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}" deleted.'
|
|
1023
|
-
logger.debug(details)
|
|
1024
1005
|
|
|
1025
1006
|
# Check if either node is ErrorProxyNode and mark connection modification (deletes are always user-initiated)
|
|
1026
1007
|
if isinstance(source_node, ErrorProxyNode):
|
|
@@ -1028,16 +1009,14 @@ class FlowManager:
|
|
|
1028
1009
|
if isinstance(target_node, ErrorProxyNode):
|
|
1029
1010
|
target_node.set_post_init_connections_modified()
|
|
1030
1011
|
|
|
1031
|
-
result = DeleteConnectionResultSuccess()
|
|
1012
|
+
result = DeleteConnectionResultSuccess(result_details=details)
|
|
1032
1013
|
return result
|
|
1033
1014
|
|
|
1034
1015
|
async def on_start_flow_request(self, request: StartFlowRequest) -> ResultPayload: # noqa: C901, PLR0911, PLR0912
|
|
1035
1016
|
# which flow
|
|
1036
1017
|
flow_name = request.flow_name
|
|
1037
|
-
debug_mode = request.debug_mode
|
|
1038
1018
|
if not flow_name:
|
|
1039
1019
|
details = "Must provide flow name to start a flow."
|
|
1040
|
-
logger.error(details)
|
|
1041
1020
|
|
|
1042
1021
|
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1043
1022
|
# get the flow by ID
|
|
@@ -1045,12 +1024,10 @@ class FlowManager:
|
|
|
1045
1024
|
flow = self.get_flow_by_name(flow_name)
|
|
1046
1025
|
except KeyError as err:
|
|
1047
1026
|
details = f"Cannot start flow. Error: {err}"
|
|
1048
|
-
logger.error(details)
|
|
1049
1027
|
return StartFlowResultFailure(validation_exceptions=[err], result_details=details)
|
|
1050
1028
|
# Check to see if the flow is already running.
|
|
1051
1029
|
if self.check_for_existing_running_flow():
|
|
1052
1030
|
details = "Cannot start flow. Flow is already running."
|
|
1053
|
-
logger.error(details)
|
|
1054
1031
|
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1055
1032
|
# A node has been provided to either start or to run up to.
|
|
1056
1033
|
if request.flow_node_name:
|
|
@@ -1058,14 +1035,12 @@ class FlowManager:
|
|
|
1058
1035
|
flow_node = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(flow_node_name, BaseNode)
|
|
1059
1036
|
if not flow_node:
|
|
1060
1037
|
details = f"Provided node with name {flow_node_name} does not exist"
|
|
1061
|
-
logger.error(details)
|
|
1062
1038
|
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1063
1039
|
# lets get the first control node in the flow!
|
|
1064
1040
|
start_node = self.get_start_node_from_node(flow, flow_node)
|
|
1065
1041
|
# if the start is not the node provided, set a breakpoint at the stop (we're running up until there)
|
|
1066
1042
|
if not start_node:
|
|
1067
1043
|
details = f"Start node for node with name {flow_node_name} does not exist"
|
|
1068
|
-
logger.error(details)
|
|
1069
1044
|
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1070
1045
|
if start_node != flow_node:
|
|
1071
1046
|
flow_node.stop_flow = True
|
|
@@ -1081,8 +1056,7 @@ class FlowManager:
|
|
|
1081
1056
|
try:
|
|
1082
1057
|
if not result.succeeded():
|
|
1083
1058
|
details = f"Couldn't start flow with name {flow_name}. Flow Validation Failed"
|
|
1084
|
-
|
|
1085
|
-
return StartFlowResultFailure(validation_exceptions=[])
|
|
1059
|
+
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1086
1060
|
result = cast("ValidateFlowDependenciesResultSuccess", result)
|
|
1087
1061
|
|
|
1088
1062
|
if not result.validation_succeeded:
|
|
@@ -1090,85 +1064,74 @@ class FlowManager:
|
|
|
1090
1064
|
if len(result.exceptions) > 0:
|
|
1091
1065
|
for exception in result.exceptions:
|
|
1092
1066
|
details = f"{details}\n\t{exception}"
|
|
1093
|
-
logger.error(details)
|
|
1094
1067
|
return StartFlowResultFailure(validation_exceptions=result.exceptions, result_details=details)
|
|
1095
1068
|
except Exception as e:
|
|
1096
1069
|
details = f"Couldn't start flow with name {flow_name}. Flow Validation Failed: {e}"
|
|
1097
|
-
logger.error(details)
|
|
1098
1070
|
return StartFlowResultFailure(validation_exceptions=[e], result_details=details)
|
|
1099
1071
|
# By now, it has been validated with no exceptions.
|
|
1100
1072
|
try:
|
|
1101
|
-
await self.start_flow(flow, start_node, debug_mode)
|
|
1073
|
+
await self.start_flow(flow, start_node, debug_mode=request.debug_mode)
|
|
1102
1074
|
except Exception as e:
|
|
1103
1075
|
details = f"Failed to kick off flow with name {flow_name}. Exception occurred: {e} "
|
|
1104
|
-
logger.error(details)
|
|
1105
1076
|
return StartFlowResultFailure(validation_exceptions=[e], result_details=details)
|
|
1106
1077
|
|
|
1107
1078
|
details = f"Successfully kicked off flow with name {flow_name}"
|
|
1108
|
-
logger.debug(details)
|
|
1109
1079
|
|
|
1110
|
-
return StartFlowResultSuccess()
|
|
1080
|
+
return StartFlowResultSuccess(result_details=details)
|
|
1111
1081
|
|
|
1112
1082
|
def on_get_flow_state_request(self, event: GetFlowStateRequest) -> ResultPayload:
|
|
1113
1083
|
flow_name = event.flow_name
|
|
1114
1084
|
if not flow_name:
|
|
1115
1085
|
details = "Could not get flow state. No flow name was provided."
|
|
1116
|
-
logger.error(details)
|
|
1117
1086
|
return GetFlowStateResultFailure(result_details=details)
|
|
1118
1087
|
try:
|
|
1119
1088
|
flow = self.get_flow_by_name(flow_name)
|
|
1120
1089
|
except KeyError as err:
|
|
1121
1090
|
details = f"Could not get flow state. Error: {err}"
|
|
1122
|
-
logger.error(details)
|
|
1123
1091
|
return GetFlowStateResultFailure(result_details=details)
|
|
1124
1092
|
try:
|
|
1125
|
-
|
|
1093
|
+
control_nodes, resolving_nodes = self.flow_state(flow)
|
|
1126
1094
|
except Exception as e:
|
|
1127
1095
|
details = f"Failed to get flow state of flow with name {flow_name}. Exception occurred: {e} "
|
|
1128
1096
|
logger.exception(details)
|
|
1129
1097
|
return GetFlowStateResultFailure(result_details=details)
|
|
1130
1098
|
details = f"Successfully got flow state for flow with name {flow_name}."
|
|
1131
|
-
|
|
1132
|
-
|
|
1099
|
+
return GetFlowStateResultSuccess(
|
|
1100
|
+
control_nodes=control_nodes, resolving_node=resolving_nodes, result_details=details
|
|
1101
|
+
)
|
|
1133
1102
|
|
|
1134
1103
|
def on_cancel_flow_request(self, request: CancelFlowRequest) -> ResultPayload:
|
|
1135
1104
|
flow_name = request.flow_name
|
|
1136
1105
|
if not flow_name:
|
|
1137
1106
|
details = "Could not cancel flow execution. No flow name was provided."
|
|
1138
|
-
logger.error(details)
|
|
1139
1107
|
|
|
1140
1108
|
return CancelFlowResultFailure(result_details=details)
|
|
1141
1109
|
try:
|
|
1142
1110
|
self.get_flow_by_name(flow_name)
|
|
1143
1111
|
except KeyError as err:
|
|
1144
1112
|
details = f"Could not cancel flow execution. Error: {err}"
|
|
1145
|
-
logger.error(details)
|
|
1146
1113
|
|
|
1147
1114
|
return CancelFlowResultFailure(result_details=details)
|
|
1148
1115
|
try:
|
|
1149
1116
|
self.cancel_flow_run()
|
|
1150
1117
|
except Exception as e:
|
|
1151
1118
|
details = f"Could not cancel flow execution. Exception: {e}"
|
|
1152
|
-
logger.error(details)
|
|
1153
1119
|
|
|
1154
1120
|
return CancelFlowResultFailure(result_details=details)
|
|
1155
1121
|
details = f"Successfully cancelled flow execution with name {flow_name}"
|
|
1156
|
-
logger.debug(details)
|
|
1157
1122
|
|
|
1158
|
-
return CancelFlowResultSuccess()
|
|
1123
|
+
return CancelFlowResultSuccess(result_details=details)
|
|
1159
1124
|
|
|
1160
1125
|
async def on_single_node_step_request(self, request: SingleNodeStepRequest) -> ResultPayload:
|
|
1161
1126
|
flow_name = request.flow_name
|
|
1162
1127
|
if not flow_name:
|
|
1163
1128
|
details = "Could not advance to the next step of a running workflow. No flow name was provided."
|
|
1164
|
-
logger.error(details)
|
|
1165
1129
|
|
|
1166
1130
|
return SingleNodeStepResultFailure(validation_exceptions=[], result_details=details)
|
|
1167
1131
|
try:
|
|
1168
1132
|
self.get_flow_by_name(flow_name)
|
|
1169
1133
|
except KeyError as err:
|
|
1170
1134
|
details = f"Could not advance to the next step of a running workflow. No flow with name {flow_name} exists. Error: {err}"
|
|
1171
|
-
logger.error(details)
|
|
1172
1135
|
|
|
1173
1136
|
return SingleNodeStepResultFailure(validation_exceptions=[err], result_details=details)
|
|
1174
1137
|
try:
|
|
@@ -1176,27 +1139,23 @@ class FlowManager:
|
|
|
1176
1139
|
await self.single_node_step(flow)
|
|
1177
1140
|
except Exception as e:
|
|
1178
1141
|
details = f"Could not advance to the next step of a running workflow. Exception: {e}"
|
|
1179
|
-
logger.error(details)
|
|
1180
1142
|
return SingleNodeStepResultFailure(validation_exceptions=[], result_details=details)
|
|
1181
1143
|
|
|
1182
1144
|
# All completed happily
|
|
1183
1145
|
details = f"Successfully advanced to the next step of a running workflow with name {flow_name}"
|
|
1184
|
-
logger.debug(details)
|
|
1185
1146
|
|
|
1186
|
-
return SingleNodeStepResultSuccess()
|
|
1147
|
+
return SingleNodeStepResultSuccess(result_details=details)
|
|
1187
1148
|
|
|
1188
1149
|
async def on_single_execution_step_request(self, request: SingleExecutionStepRequest) -> ResultPayload:
|
|
1189
1150
|
flow_name = request.flow_name
|
|
1190
1151
|
if not flow_name:
|
|
1191
1152
|
details = "Could not advance to the next step of a running workflow. No flow name was provided."
|
|
1192
|
-
logger.error(details)
|
|
1193
1153
|
|
|
1194
1154
|
return SingleExecutionStepResultFailure(result_details=details)
|
|
1195
1155
|
try:
|
|
1196
1156
|
flow = self.get_flow_by_name(flow_name)
|
|
1197
1157
|
except KeyError as err:
|
|
1198
1158
|
details = f"Could not advance to the next step of a running workflow. Error: {err}."
|
|
1199
|
-
logger.error(details)
|
|
1200
1159
|
|
|
1201
1160
|
return SingleExecutionStepResultFailure(result_details=details)
|
|
1202
1161
|
change_debug_mode = request.request_id is not None
|
|
@@ -1209,61 +1168,50 @@ class FlowManager:
|
|
|
1209
1168
|
self.cancel_flow_run()
|
|
1210
1169
|
except Exception as e_inner:
|
|
1211
1170
|
details = f"Could not cancel flow execution. Exception: {e_inner}"
|
|
1212
|
-
logger.error(details)
|
|
1213
1171
|
|
|
1214
1172
|
details = f"Could not advance to the next step of a running workflow. Exception: {e}"
|
|
1215
|
-
logger.error(details)
|
|
1216
1173
|
return SingleNodeStepResultFailure(validation_exceptions=[e], result_details=details)
|
|
1217
1174
|
details = f"Successfully advanced to the next step of a running workflow with name {flow_name}"
|
|
1218
|
-
logger.debug(details)
|
|
1219
1175
|
|
|
1220
|
-
return SingleExecutionStepResultSuccess()
|
|
1176
|
+
return SingleExecutionStepResultSuccess(result_details=details)
|
|
1221
1177
|
|
|
1222
1178
|
async def on_continue_execution_step_request(self, request: ContinueExecutionStepRequest) -> ResultPayload:
|
|
1223
1179
|
flow_name = request.flow_name
|
|
1224
1180
|
if not flow_name:
|
|
1225
1181
|
details = "Failed to continue execution step because no flow name was provided"
|
|
1226
|
-
logger.error(details)
|
|
1227
1182
|
|
|
1228
1183
|
return ContinueExecutionStepResultFailure(result_details=details)
|
|
1229
1184
|
try:
|
|
1230
1185
|
flow = self.get_flow_by_name(flow_name)
|
|
1231
1186
|
except KeyError as err:
|
|
1232
1187
|
details = f"Failed to continue execution step. Error: {err}"
|
|
1233
|
-
logger.error(details)
|
|
1234
1188
|
|
|
1235
1189
|
return ContinueExecutionStepResultFailure(result_details=details)
|
|
1236
1190
|
try:
|
|
1237
1191
|
await self.continue_executing(flow)
|
|
1238
1192
|
except Exception as e:
|
|
1239
1193
|
details = f"Failed to continue execution step. An exception occurred: {e}."
|
|
1240
|
-
logger.error(details)
|
|
1241
1194
|
return ContinueExecutionStepResultFailure(result_details=details)
|
|
1242
1195
|
details = f"Successfully continued flow with name {flow_name}"
|
|
1243
|
-
|
|
1244
|
-
return ContinueExecutionStepResultSuccess()
|
|
1196
|
+
return ContinueExecutionStepResultSuccess(result_details=details)
|
|
1245
1197
|
|
|
1246
1198
|
def on_unresolve_flow_request(self, request: UnresolveFlowRequest) -> ResultPayload:
|
|
1247
1199
|
flow_name = request.flow_name
|
|
1248
1200
|
if not flow_name:
|
|
1249
1201
|
details = "Failed to unresolve flow because no flow name was provided"
|
|
1250
|
-
logger.error(details)
|
|
1251
1202
|
return UnresolveFlowResultFailure(result_details=details)
|
|
1252
1203
|
try:
|
|
1253
1204
|
flow = self.get_flow_by_name(flow_name)
|
|
1254
1205
|
except KeyError as err:
|
|
1255
1206
|
details = f"Failed to unresolve flow. Error: {err}"
|
|
1256
|
-
logger.error(details)
|
|
1257
1207
|
return UnresolveFlowResultFailure(result_details=details)
|
|
1258
1208
|
try:
|
|
1259
1209
|
self.unresolve_whole_flow(flow)
|
|
1260
1210
|
except Exception as e:
|
|
1261
1211
|
details = f"Failed to unresolve flow. An exception occurred: {e}."
|
|
1262
|
-
logger.error(details)
|
|
1263
1212
|
return UnresolveFlowResultFailure(result_details=details)
|
|
1264
1213
|
details = f"Unresolved flow with name {flow_name}"
|
|
1265
|
-
|
|
1266
|
-
return UnresolveFlowResultSuccess()
|
|
1214
|
+
return UnresolveFlowResultSuccess(result_details=details)
|
|
1267
1215
|
|
|
1268
1216
|
async def on_validate_flow_dependencies_request(self, request: ValidateFlowDependenciesRequest) -> ResultPayload:
|
|
1269
1217
|
flow_name = request.flow_name
|
|
@@ -1272,14 +1220,12 @@ class FlowManager:
|
|
|
1272
1220
|
flow = self.get_flow_by_name(flow_name)
|
|
1273
1221
|
except KeyError as err:
|
|
1274
1222
|
details = f"Failed to validate flow. Error: {err}"
|
|
1275
|
-
logger.error(details)
|
|
1276
1223
|
return ValidateFlowDependenciesResultFailure(result_details=details)
|
|
1277
1224
|
if request.flow_node_name:
|
|
1278
1225
|
flow_node_name = request.flow_node_name
|
|
1279
1226
|
flow_node = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(flow_node_name, BaseNode)
|
|
1280
1227
|
if not flow_node:
|
|
1281
1228
|
details = f"Provided node with name {flow_node_name} does not exist"
|
|
1282
|
-
logger.error(details)
|
|
1283
1229
|
return ValidateFlowDependenciesResultFailure(result_details=details)
|
|
1284
1230
|
# Gets all nodes in that connected group to be ran
|
|
1285
1231
|
nodes = flow.get_all_connected_nodes(flow_node)
|
|
@@ -1292,13 +1238,14 @@ class FlowManager:
|
|
|
1292
1238
|
if exceptions:
|
|
1293
1239
|
all_exceptions = all_exceptions + exceptions
|
|
1294
1240
|
return ValidateFlowDependenciesResultSuccess(
|
|
1295
|
-
validation_succeeded=len(all_exceptions) == 0,
|
|
1241
|
+
validation_succeeded=len(all_exceptions) == 0,
|
|
1242
|
+
exceptions=all_exceptions,
|
|
1243
|
+
result_details=f"Validated flow dependencies: {len(all_exceptions)} exceptions found",
|
|
1296
1244
|
)
|
|
1297
1245
|
|
|
1298
1246
|
def on_list_flows_in_current_context_request(self, request: ListFlowsInCurrentContextRequest) -> ResultPayload: # noqa: ARG002 (request isn't actually used)
|
|
1299
1247
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
1300
1248
|
details = "Attempted to list Flows in the Current Context. Failed because the Current Context was empty."
|
|
1301
|
-
logger.error(details)
|
|
1302
1249
|
return ListFlowsInCurrentContextResultFailure(result_details=details)
|
|
1303
1250
|
|
|
1304
1251
|
parent_flow = GriptapeNodes.ContextManager().get_current_flow()
|
|
@@ -1311,9 +1258,8 @@ class FlowManager:
|
|
|
1311
1258
|
ret_list.append(flow_name)
|
|
1312
1259
|
|
|
1313
1260
|
details = f"Successfully got the list of Flows in the Current Context (Flow '{parent_flow_name}')."
|
|
1314
|
-
logger.debug(details)
|
|
1315
1261
|
|
|
1316
|
-
return ListFlowsInCurrentContextResultSuccess(flow_names=ret_list)
|
|
1262
|
+
return ListFlowsInCurrentContextResultSuccess(flow_names=ret_list, result_details=details)
|
|
1317
1263
|
|
|
1318
1264
|
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/861
|
|
1319
1265
|
# similar manager refactors: https://github.com/griptape-ai/griptape-nodes/issues/806
|
|
@@ -1326,7 +1272,6 @@ class FlowManager:
|
|
|
1326
1272
|
flow_name = flow.name
|
|
1327
1273
|
else:
|
|
1328
1274
|
details = "Attempted to serialize a Flow to commands from the Current Context. Failed because the Current Context was empty."
|
|
1329
|
-
logger.error(details)
|
|
1330
1275
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1331
1276
|
if flow is None:
|
|
1332
1277
|
# Does this flow exist?
|
|
@@ -1335,7 +1280,6 @@ class FlowManager:
|
|
|
1335
1280
|
details = (
|
|
1336
1281
|
f"Attempted to serialize Flow '{flow_name}' to commands, but no Flow with that name could be found."
|
|
1337
1282
|
)
|
|
1338
|
-
logger.error(details)
|
|
1339
1283
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1340
1284
|
|
|
1341
1285
|
# Track all node libraries that were in use by these Nodes
|
|
@@ -1381,7 +1325,6 @@ class FlowManager:
|
|
|
1381
1325
|
details = (
|
|
1382
1326
|
f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to list Nodes in the Flow."
|
|
1383
1327
|
)
|
|
1384
|
-
logger.error(details)
|
|
1385
1328
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1386
1329
|
|
|
1387
1330
|
# Serialize each node
|
|
@@ -1389,7 +1332,6 @@ class FlowManager:
|
|
|
1389
1332
|
node = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(node_name, BaseNode)
|
|
1390
1333
|
if node is None:
|
|
1391
1334
|
details = f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to serialize Node '{node_name}' within the Flow."
|
|
1392
|
-
logger.error(details)
|
|
1393
1335
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1394
1336
|
with GriptapeNodes.ContextManager().node(node):
|
|
1395
1337
|
# Note: the parameter value stuff is pass-by-reference, and we expect the values to be modified in place.
|
|
@@ -1401,7 +1343,6 @@ class FlowManager:
|
|
|
1401
1343
|
serialize_node_result = GriptapeNodes.handle_request(serialize_node_request)
|
|
1402
1344
|
if not isinstance(serialize_node_result, SerializeNodeToCommandsResultSuccess):
|
|
1403
1345
|
details = f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to serialize Node '{node_name}' within the Flow."
|
|
1404
|
-
logger.error(details)
|
|
1405
1346
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1406
1347
|
|
|
1407
1348
|
serialized_node = serialize_node_result.serialized_node_commands
|
|
@@ -1441,7 +1382,6 @@ class FlowManager:
|
|
|
1441
1382
|
flows_in_flow_result = GriptapeNodes().handle_request(flows_in_flow_request)
|
|
1442
1383
|
if not isinstance(flows_in_flow_result, ListFlowsInFlowResultSuccess):
|
|
1443
1384
|
details = f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to list child Flows in the Flow."
|
|
1444
|
-
logger.error(details)
|
|
1445
1385
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1446
1386
|
|
|
1447
1387
|
sub_flow_commands = []
|
|
@@ -1449,7 +1389,6 @@ class FlowManager:
|
|
|
1449
1389
|
flow = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(child_flow, ControlFlow)
|
|
1450
1390
|
if flow is None:
|
|
1451
1391
|
details = f"Attempted to serialize Flow '{flow_name}', but no Flow with that name could be found."
|
|
1452
|
-
logger.error(details)
|
|
1453
1392
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1454
1393
|
|
|
1455
1394
|
# Check if this is a referenced workflow
|
|
@@ -1482,8 +1421,7 @@ class FlowManager:
|
|
|
1482
1421
|
child_flow_result = GriptapeNodes().handle_request(child_flow_request)
|
|
1483
1422
|
if not isinstance(child_flow_result, SerializeFlowToCommandsResultSuccess):
|
|
1484
1423
|
details = f"Attempted to serialize parent flow '{flow_name}'. Failed while serializing child flow '{child_flow}'."
|
|
1485
|
-
|
|
1486
|
-
return SerializeFlowToCommandsResultFailure()
|
|
1424
|
+
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1487
1425
|
serialized_flow = child_flow_result.serialized_flow_commands
|
|
1488
1426
|
sub_flow_commands.append(serialized_flow)
|
|
1489
1427
|
|
|
@@ -1505,7 +1443,7 @@ class FlowManager:
|
|
|
1505
1443
|
referenced_workflows=referenced_workflows_in_use,
|
|
1506
1444
|
)
|
|
1507
1445
|
details = f"Successfully serialized Flow '{flow_name}' into commands."
|
|
1508
|
-
result = SerializeFlowToCommandsResultSuccess(serialized_flow_commands=serialized_flow)
|
|
1446
|
+
result = SerializeFlowToCommandsResultSuccess(serialized_flow_commands=serialized_flow, result_details=details)
|
|
1509
1447
|
return result
|
|
1510
1448
|
|
|
1511
1449
|
def on_deserialize_flow_from_commands(self, request: DeserializeFlowFromCommandsRequest) -> ResultPayload: # noqa: C901, PLR0911, PLR0912, PLR0915 (I am big and complicated and have a lot of negative edge-cases)
|
|
@@ -1516,7 +1454,6 @@ class FlowManager:
|
|
|
1516
1454
|
flow_name = flow.name
|
|
1517
1455
|
else:
|
|
1518
1456
|
details = "Attempted to deserialize a set of Flow Creation commands into the Current Context. Failed because the Current Context was empty."
|
|
1519
|
-
logger.error(details)
|
|
1520
1457
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1521
1458
|
else:
|
|
1522
1459
|
# Issue the creation command first.
|
|
@@ -1528,25 +1465,21 @@ class FlowManager:
|
|
|
1528
1465
|
case CreateFlowRequest():
|
|
1529
1466
|
if not isinstance(flow_initialization_result, CreateFlowResultSuccess):
|
|
1530
1467
|
details = f"Attempted to deserialize a serialized set of Flow Creation commands. Failed to create flow '{flow_initialization_command.flow_name}'."
|
|
1531
|
-
logger.error(details)
|
|
1532
1468
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1533
1469
|
flow_name = flow_initialization_result.flow_name
|
|
1534
1470
|
case ImportWorkflowAsReferencedSubFlowRequest():
|
|
1535
1471
|
if not isinstance(flow_initialization_result, ImportWorkflowAsReferencedSubFlowResultSuccess):
|
|
1536
1472
|
details = f"Attempted to deserialize a serialized set of Flow Creation commands. Failed to import workflow '{flow_initialization_command.workflow_name}'."
|
|
1537
|
-
logger.error(details)
|
|
1538
1473
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1539
1474
|
flow_name = flow_initialization_result.created_flow_name
|
|
1540
1475
|
case _:
|
|
1541
1476
|
details = f"Attempted to deserialize Flow Creation commands with unknown command type: {type(flow_initialization_command).__name__}."
|
|
1542
|
-
logger.error(details)
|
|
1543
1477
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1544
1478
|
|
|
1545
1479
|
# Adopt the newly-created flow as our current context.
|
|
1546
1480
|
flow = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(flow_name, ControlFlow)
|
|
1547
1481
|
if flow is None:
|
|
1548
1482
|
details = f"Attempted to deserialize a serialized set of Flow Creation commands. Failed to find created flow '{flow_name}'."
|
|
1549
|
-
logger.error(details)
|
|
1550
1483
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1551
1484
|
GriptapeNodes.ContextManager().push_flow(flow=flow)
|
|
1552
1485
|
|
|
@@ -1562,7 +1495,6 @@ class FlowManager:
|
|
|
1562
1495
|
details = (
|
|
1563
1496
|
f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a node within the flow."
|
|
1564
1497
|
)
|
|
1565
|
-
logger.error(details)
|
|
1566
1498
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1567
1499
|
node_uuid_to_deserialized_node_result[serialized_node.node_uuid] = deserialized_node_result
|
|
1568
1500
|
|
|
@@ -1574,12 +1506,10 @@ class FlowManager:
|
|
|
1574
1506
|
source_node_uuid = indirect_connection.source_node_uuid
|
|
1575
1507
|
if source_node_uuid not in node_uuid_to_deserialized_node_result:
|
|
1576
1508
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while attempting to create a Connection for a source node that did not exist within the flow."
|
|
1577
|
-
logger.error(details)
|
|
1578
1509
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1579
1510
|
target_node_uuid = indirect_connection.target_node_uuid
|
|
1580
1511
|
if target_node_uuid not in node_uuid_to_deserialized_node_result:
|
|
1581
1512
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while attempting to create a Connection for a target node that did not exist within the flow."
|
|
1582
|
-
logger.error(details)
|
|
1583
1513
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1584
1514
|
|
|
1585
1515
|
source_node_result = node_uuid_to_deserialized_node_result[source_node_uuid]
|
|
@@ -1596,7 +1526,6 @@ class FlowManager:
|
|
|
1596
1526
|
create_connection_result = GriptapeNodes.handle_request(create_connection_request)
|
|
1597
1527
|
if create_connection_result.failed():
|
|
1598
1528
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a Connection from '{source_node_name}.{indirect_connection.source_parameter_name}' to '{target_node_name}.{indirect_connection.target_parameter_name}' within the flow."
|
|
1599
|
-
logger.error(details)
|
|
1600
1529
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1601
1530
|
|
|
1602
1531
|
# Now assign the values.
|
|
@@ -1610,7 +1539,6 @@ class FlowManager:
|
|
|
1610
1539
|
node = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(node_name, BaseNode)
|
|
1611
1540
|
if node is None:
|
|
1612
1541
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a value assignment for node '{node_name}'."
|
|
1613
|
-
logger.error(details)
|
|
1614
1542
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1615
1543
|
with GriptapeNodes.ContextManager().node(node=node):
|
|
1616
1544
|
# Iterate through each set value command in the list for this node.
|
|
@@ -1621,7 +1549,6 @@ class FlowManager:
|
|
|
1621
1549
|
value = request.serialized_flow_commands.unique_parameter_uuid_to_values[unique_value_uuid]
|
|
1622
1550
|
except IndexError as err:
|
|
1623
1551
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a value assignment for node '{node.name}.{parameter_name}': {err}"
|
|
1624
|
-
logger.error(details)
|
|
1625
1552
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1626
1553
|
|
|
1627
1554
|
# Call the SetParameterValueRequest, subbing in the value from our unique value list.
|
|
@@ -1631,7 +1558,6 @@ class FlowManager:
|
|
|
1631
1558
|
)
|
|
1632
1559
|
if set_parameter_value_result.failed():
|
|
1633
1560
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a value assignment for node '{node.name}.{parameter_name}'."
|
|
1634
|
-
logger.error(details)
|
|
1635
1561
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1636
1562
|
|
|
1637
1563
|
# Now the child flows.
|
|
@@ -1640,12 +1566,10 @@ class FlowManager:
|
|
|
1640
1566
|
sub_flow_result = GriptapeNodes.handle_request(sub_flow_request)
|
|
1641
1567
|
if sub_flow_result.failed():
|
|
1642
1568
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a sub-flow within the Flow."
|
|
1643
|
-
logger.error(details)
|
|
1644
1569
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1645
1570
|
|
|
1646
1571
|
details = f"Successfully deserialized Flow '{flow_name}'."
|
|
1647
|
-
|
|
1648
|
-
return DeserializeFlowFromCommandsResultSuccess(flow_name=flow_name)
|
|
1572
|
+
return DeserializeFlowFromCommandsResultSuccess(flow_name=flow_name, result_details=details)
|
|
1649
1573
|
|
|
1650
1574
|
def on_flush_request(self, request: FlushParameterChangesRequest) -> ResultPayload: # noqa: ARG002
|
|
1651
1575
|
obj_manager = GriptapeNodes.ObjectManager()
|
|
@@ -1656,9 +1580,15 @@ class FlowManager:
|
|
|
1656
1580
|
# Only flush if there are actually tracked parameters
|
|
1657
1581
|
if node._tracked_parameters:
|
|
1658
1582
|
node.emit_parameter_changes()
|
|
1659
|
-
return FlushParameterChangesResultSuccess()
|
|
1583
|
+
return FlushParameterChangesResultSuccess(result_details="Parameter changes flushed successfully.")
|
|
1660
1584
|
|
|
1661
|
-
async def start_flow(
|
|
1585
|
+
async def start_flow(
|
|
1586
|
+
self,
|
|
1587
|
+
flow: ControlFlow,
|
|
1588
|
+
start_node: BaseNode | None = None,
|
|
1589
|
+
*,
|
|
1590
|
+
debug_mode: bool = False,
|
|
1591
|
+
) -> None:
|
|
1662
1592
|
if self.check_for_existing_running_flow():
|
|
1663
1593
|
# If flow already exists, throw an error
|
|
1664
1594
|
errormsg = "This workflow is already in progress. Please wait for the current process to finish before starting again."
|
|
@@ -1668,13 +1598,13 @@ class FlowManager:
|
|
|
1668
1598
|
if self._global_flow_queue.empty():
|
|
1669
1599
|
errormsg = "No Flow exists. You must create at least one control connection."
|
|
1670
1600
|
raise RuntimeError(errormsg)
|
|
1671
|
-
|
|
1601
|
+
queue_item = self._global_flow_queue.get()
|
|
1602
|
+
start_node = queue_item.node
|
|
1672
1603
|
self._global_flow_queue.task_done()
|
|
1673
1604
|
|
|
1674
|
-
# Initialize global control flow machine
|
|
1675
|
-
if self._global_control_flow_machine is None:
|
|
1676
|
-
self._global_control_flow_machine = ControlFlowMachine()
|
|
1605
|
+
# Initialize global control flow machine and DAG builder
|
|
1677
1606
|
|
|
1607
|
+
self._global_control_flow_machine = ControlFlowMachine(flow.name)
|
|
1678
1608
|
try:
|
|
1679
1609
|
await self._global_control_flow_machine.start_flow(start_node, debug_mode)
|
|
1680
1610
|
except Exception:
|
|
@@ -1685,15 +1615,13 @@ class FlowManager:
|
|
|
1685
1615
|
def check_for_existing_running_flow(self) -> bool:
|
|
1686
1616
|
if self._global_control_flow_machine is None:
|
|
1687
1617
|
return False
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
and self._global_control_flow_machine._current_state
|
|
1691
|
-
):
|
|
1618
|
+
current_state = self._global_control_flow_machine.current_state
|
|
1619
|
+
if current_state and current_state is not CompleteState:
|
|
1692
1620
|
# Flow already exists in progress
|
|
1693
1621
|
return True
|
|
1694
1622
|
return bool(
|
|
1695
|
-
not self._global_control_flow_machine.
|
|
1696
|
-
and self._global_control_flow_machine.
|
|
1623
|
+
not self._global_control_flow_machine.context.resolution_machine.is_complete()
|
|
1624
|
+
and self._global_control_flow_machine.context.resolution_machine.is_started()
|
|
1697
1625
|
)
|
|
1698
1626
|
|
|
1699
1627
|
def cancel_flow_run(self) -> None:
|
|
@@ -1701,10 +1629,11 @@ class FlowManager:
|
|
|
1701
1629
|
errormsg = "Flow has not yet been started. Cannot cancel flow that hasn't begun."
|
|
1702
1630
|
raise RuntimeError(errormsg)
|
|
1703
1631
|
self._global_flow_queue.queue.clear()
|
|
1704
|
-
if self._global_control_flow_machine is not None:
|
|
1705
|
-
self._global_control_flow_machine.reset_machine()
|
|
1706
1632
|
# Reset control flow machine
|
|
1633
|
+
if self._global_control_flow_machine is not None:
|
|
1634
|
+
self._global_control_flow_machine.reset_machine(cancel=True)
|
|
1707
1635
|
self._global_single_node_resolution = False
|
|
1636
|
+
self._global_dag_builder.clear()
|
|
1708
1637
|
logger.debug("Cancelling flow run")
|
|
1709
1638
|
|
|
1710
1639
|
GriptapeNodes.EventManager().put_event(
|
|
@@ -1716,7 +1645,7 @@ class FlowManager:
|
|
|
1716
1645
|
self._global_flow_queue.queue.clear()
|
|
1717
1646
|
if self._global_control_flow_machine is not None:
|
|
1718
1647
|
self._global_control_flow_machine.reset_machine()
|
|
1719
|
-
|
|
1648
|
+
# Reset control flow machine
|
|
1720
1649
|
self._global_single_node_resolution = False
|
|
1721
1650
|
|
|
1722
1651
|
# Clear all connections to prevent memory leaks and stale references
|
|
@@ -1735,9 +1664,9 @@ class FlowManager:
|
|
|
1735
1664
|
"""Get the next node from the global execution queue, or None if empty."""
|
|
1736
1665
|
if self._global_flow_queue.empty():
|
|
1737
1666
|
return None
|
|
1738
|
-
|
|
1667
|
+
queue_item = self._global_flow_queue.get()
|
|
1739
1668
|
self._global_flow_queue.task_done()
|
|
1740
|
-
return node
|
|
1669
|
+
return queue_item.node
|
|
1741
1670
|
|
|
1742
1671
|
def clear_execution_queue(self) -> None:
|
|
1743
1672
|
"""Clear all nodes from the global execution queue."""
|
|
@@ -1756,7 +1685,7 @@ class FlowManager:
|
|
|
1756
1685
|
# Internal execution queue helper methods to consolidate redundant operations
|
|
1757
1686
|
async def _handle_flow_start_if_not_running(
|
|
1758
1687
|
self,
|
|
1759
|
-
flow: ControlFlow,
|
|
1688
|
+
flow: ControlFlow,
|
|
1760
1689
|
*,
|
|
1761
1690
|
debug_mode: bool,
|
|
1762
1691
|
error_message: str,
|
|
@@ -1765,42 +1694,47 @@ class FlowManager:
|
|
|
1765
1694
|
if not self.check_for_existing_running_flow():
|
|
1766
1695
|
if self._global_flow_queue.empty():
|
|
1767
1696
|
raise RuntimeError(error_message)
|
|
1768
|
-
|
|
1697
|
+
queue_item = self._global_flow_queue.get()
|
|
1698
|
+
start_node = queue_item.node
|
|
1769
1699
|
self._global_flow_queue.task_done()
|
|
1700
|
+
# Get or create machine
|
|
1770
1701
|
if self._global_control_flow_machine is None:
|
|
1771
|
-
self._global_control_flow_machine = ControlFlowMachine()
|
|
1702
|
+
self._global_control_flow_machine = ControlFlowMachine(flow.name)
|
|
1772
1703
|
await self._global_control_flow_machine.start_flow(start_node, debug_mode)
|
|
1773
1704
|
|
|
1774
1705
|
async def _handle_post_execution_queue_processing(self, *, debug_mode: bool) -> None:
|
|
1775
1706
|
"""Handle execution queue processing after execution completes."""
|
|
1776
1707
|
if not self.check_for_existing_running_flow() and not self._global_flow_queue.empty():
|
|
1777
|
-
|
|
1708
|
+
queue_item = self._global_flow_queue.get()
|
|
1709
|
+
start_node = queue_item.node
|
|
1778
1710
|
self._global_flow_queue.task_done()
|
|
1779
|
-
|
|
1780
|
-
|
|
1711
|
+
machine = self._global_control_flow_machine
|
|
1712
|
+
if machine is not None:
|
|
1713
|
+
await machine.start_flow(start_node, debug_mode)
|
|
1781
1714
|
|
|
1782
|
-
async def resolve_singular_node(self, flow: ControlFlow, node: BaseNode, debug_mode: bool = False) -> None:
|
|
1715
|
+
async def resolve_singular_node(self, flow: ControlFlow, node: BaseNode, *, debug_mode: bool = False) -> None:
|
|
1783
1716
|
# Set that we are only working on one node right now! no other stepping allowed
|
|
1784
1717
|
if self.check_for_existing_running_flow():
|
|
1785
1718
|
# If flow already exists, throw an error
|
|
1786
1719
|
errormsg = f"This workflow is already in progress. Please wait for the current process to finish before starting {node.name} again."
|
|
1787
1720
|
raise RuntimeError(errormsg)
|
|
1721
|
+
|
|
1788
1722
|
self._global_single_node_resolution = True
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
self._global_control_flow_machine.
|
|
1794
|
-
resolution_machine
|
|
1795
|
-
# Set debug mode
|
|
1796
|
-
resolution_machine.change_debug_mode(debug_mode)
|
|
1797
|
-
# Resolve the node.
|
|
1723
|
+
|
|
1724
|
+
# Get or create machine
|
|
1725
|
+
self._global_control_flow_machine = ControlFlowMachine(flow.name)
|
|
1726
|
+
self._global_control_flow_machine.context.current_nodes = [node]
|
|
1727
|
+
resolution_machine = self._global_control_flow_machine.resolution_machine
|
|
1728
|
+
resolution_machine.change_debug_mode(debug_mode=debug_mode)
|
|
1798
1729
|
node.state = NodeResolutionState.UNRESOLVED
|
|
1730
|
+
# Build the DAG for the node
|
|
1731
|
+
if isinstance(resolution_machine, ParallelResolutionMachine):
|
|
1732
|
+
self._global_dag_builder.add_node_with_dependencies(node)
|
|
1733
|
+
resolution_machine.context.dag_builder = self._global_dag_builder
|
|
1799
1734
|
await resolution_machine.resolve_node(node)
|
|
1800
|
-
# decide if we can change it back to normal flow mode!
|
|
1801
1735
|
if resolution_machine.is_complete():
|
|
1802
1736
|
self._global_single_node_resolution = False
|
|
1803
|
-
self._global_control_flow_machine.
|
|
1737
|
+
self._global_control_flow_machine.context.current_nodes = []
|
|
1804
1738
|
|
|
1805
1739
|
async def single_execution_step(self, flow: ControlFlow, change_debug_mode: bool) -> None: # noqa: FBT001
|
|
1806
1740
|
# do a granular step
|
|
@@ -1811,11 +1745,11 @@ class FlowManager:
|
|
|
1811
1745
|
return
|
|
1812
1746
|
if self._global_control_flow_machine is not None:
|
|
1813
1747
|
await self._global_control_flow_machine.granular_step(change_debug_mode)
|
|
1814
|
-
resolution_machine = self._global_control_flow_machine.
|
|
1748
|
+
resolution_machine = self._global_control_flow_machine.resolution_machine
|
|
1815
1749
|
if self._global_single_node_resolution:
|
|
1816
|
-
resolution_machine = self._global_control_flow_machine.
|
|
1817
|
-
|
|
1818
|
-
|
|
1750
|
+
resolution_machine = self._global_control_flow_machine.resolution_machine
|
|
1751
|
+
if resolution_machine.is_complete():
|
|
1752
|
+
self._global_single_node_resolution = False
|
|
1819
1753
|
|
|
1820
1754
|
async def single_node_step(self, flow: ControlFlow) -> None:
|
|
1821
1755
|
# It won't call single_node_step without an existing flow running from US.
|
|
@@ -1840,13 +1774,13 @@ class FlowManager:
|
|
|
1840
1774
|
if not self.check_for_existing_running_flow():
|
|
1841
1775
|
return
|
|
1842
1776
|
# Turn all debugging to false and continue on
|
|
1843
|
-
if self._global_control_flow_machine is not None:
|
|
1777
|
+
if self._global_control_flow_machine is not None and self._global_control_flow_machine is not None:
|
|
1844
1778
|
self._global_control_flow_machine.change_debug_mode(False)
|
|
1845
1779
|
if self._global_single_node_resolution:
|
|
1846
|
-
if self._global_control_flow_machine.
|
|
1780
|
+
if self._global_control_flow_machine.resolution_machine.is_complete():
|
|
1847
1781
|
self._global_single_node_resolution = False
|
|
1848
1782
|
else:
|
|
1849
|
-
await self._global_control_flow_machine.
|
|
1783
|
+
await self._global_control_flow_machine.resolution_machine.update()
|
|
1850
1784
|
else:
|
|
1851
1785
|
await self._global_control_flow_machine.node_step()
|
|
1852
1786
|
# Now it is done executing. make sure it's actually done?
|
|
@@ -1858,20 +1792,30 @@ class FlowManager:
|
|
|
1858
1792
|
# Clear entry control parameter for new execution
|
|
1859
1793
|
node.set_entry_control_parameter(None)
|
|
1860
1794
|
|
|
1861
|
-
def flow_state(self, flow: ControlFlow) -> tuple[str | None, str | None]: # noqa: ARG002
|
|
1795
|
+
def flow_state(self, flow: ControlFlow) -> tuple[list[str] | None, list[str] | None]: # noqa: ARG002
|
|
1862
1796
|
if not self.check_for_existing_running_flow():
|
|
1863
1797
|
msg = "Flow hasn't started."
|
|
1864
1798
|
raise RuntimeError(msg)
|
|
1865
1799
|
if self._global_control_flow_machine is None:
|
|
1866
1800
|
return None, None
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1801
|
+
control_flow_context = self._global_control_flow_machine.context
|
|
1802
|
+
current_control_nodes = (
|
|
1803
|
+
[control_flow_node.name for control_flow_node in control_flow_context.current_nodes]
|
|
1804
|
+
if control_flow_context.current_nodes is not None
|
|
1870
1805
|
else None
|
|
1871
1806
|
)
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1807
|
+
# focus_stack is no longer available in the new architecture
|
|
1808
|
+
if isinstance(control_flow_context.resolution_machine, ParallelResolutionMachine):
|
|
1809
|
+
current_resolving_nodes = [
|
|
1810
|
+
node.node_reference.name
|
|
1811
|
+
for node in control_flow_context.resolution_machine.context.task_to_node.values()
|
|
1812
|
+
]
|
|
1813
|
+
return current_control_nodes, current_resolving_nodes
|
|
1814
|
+
if isinstance(control_flow_context.resolution_machine, SequentialResolutionMachine):
|
|
1815
|
+
focus_stack_for_node = control_flow_context.resolution_machine.context.focus_stack
|
|
1816
|
+
current_resolving_node = focus_stack_for_node[-1].node.name if len(focus_stack_for_node) else None
|
|
1817
|
+
return current_control_nodes, [current_resolving_node] if current_resolving_node else None
|
|
1818
|
+
return current_control_nodes, None
|
|
1875
1819
|
|
|
1876
1820
|
def get_start_node_from_node(self, flow: ControlFlow, node: BaseNode) -> BaseNode | None:
|
|
1877
1821
|
# backwards chain in control outputs.
|
|
@@ -1984,13 +1928,13 @@ class FlowManager:
|
|
|
1984
1928
|
# check if it has an outgoing connection. We don't want it to (that means we get the most resolution)
|
|
1985
1929
|
if node.name not in cn_mgr.outgoing_index:
|
|
1986
1930
|
valid_data_nodes.append(node)
|
|
1987
|
-
# ok now - populate the global flow queue
|
|
1931
|
+
# ok now - populate the global flow queue with node type information
|
|
1988
1932
|
for node in start_nodes:
|
|
1989
|
-
self._global_flow_queue.put(node)
|
|
1933
|
+
self._global_flow_queue.put(QueueItem(node=node, dag_execution_type=DagExecutionType.START_NODE))
|
|
1990
1934
|
for node in control_nodes:
|
|
1991
|
-
self._global_flow_queue.put(node)
|
|
1935
|
+
self._global_flow_queue.put(QueueItem(node=node, dag_execution_type=DagExecutionType.CONTROL_NODE))
|
|
1992
1936
|
for node in valid_data_nodes:
|
|
1993
|
-
self._global_flow_queue.put(node)
|
|
1937
|
+
self._global_flow_queue.put(QueueItem(node=node, dag_execution_type=DagExecutionType.DATA_NODE))
|
|
1994
1938
|
|
|
1995
1939
|
return self._global_flow_queue
|
|
1996
1940
|
|